blob: 5e5a738ea95cfc4a5d72df868aebc5ecede9631a [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
Marcel Holtmannbeb1c212015-03-10 14:04:52 -070041#define MGMT_REVISION 9
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,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200105};
106
107static const u16 mgmt_events[] = {
108 MGMT_EV_CONTROLLER_ERROR,
109 MGMT_EV_INDEX_ADDED,
110 MGMT_EV_INDEX_REMOVED,
111 MGMT_EV_NEW_SETTINGS,
112 MGMT_EV_CLASS_OF_DEV_CHANGED,
113 MGMT_EV_LOCAL_NAME_CHANGED,
114 MGMT_EV_NEW_LINK_KEY,
115 MGMT_EV_NEW_LONG_TERM_KEY,
116 MGMT_EV_DEVICE_CONNECTED,
117 MGMT_EV_DEVICE_DISCONNECTED,
118 MGMT_EV_CONNECT_FAILED,
119 MGMT_EV_PIN_CODE_REQUEST,
120 MGMT_EV_USER_CONFIRM_REQUEST,
121 MGMT_EV_USER_PASSKEY_REQUEST,
122 MGMT_EV_AUTH_FAILED,
123 MGMT_EV_DEVICE_FOUND,
124 MGMT_EV_DISCOVERING,
125 MGMT_EV_DEVICE_BLOCKED,
126 MGMT_EV_DEVICE_UNBLOCKED,
127 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300128 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800129 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700130 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200131 MGMT_EV_DEVICE_ADDED,
132 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300133 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200134 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd38962014-07-02 21:30:55 +0200135 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200136 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700137 MGMT_EV_EXT_INDEX_ADDED,
138 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700139 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Arman Uguray24b4f382015-03-23 15:57:12 -0700140 MGMT_EV_ADVERTISING_ADDED,
141 MGMT_EV_ADVERTISING_REMOVED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200142};
143
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800144#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200145
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200146#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
147 "\x00\x00\x00\x00\x00\x00\x00\x00"
148
Johan Hedbergca69b792011-11-11 18:10:00 +0200149/* HCI to MGMT error code conversion table */
150static u8 mgmt_status_table[] = {
151 MGMT_STATUS_SUCCESS,
152 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
153 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
154 MGMT_STATUS_FAILED, /* Hardware Failure */
155 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
156 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200157 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200158 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
159 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
160 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
161 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
162 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
163 MGMT_STATUS_BUSY, /* Command Disallowed */
164 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
165 MGMT_STATUS_REJECTED, /* Rejected Security */
166 MGMT_STATUS_REJECTED, /* Rejected Personal */
167 MGMT_STATUS_TIMEOUT, /* Host Timeout */
168 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
169 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
170 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
171 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
172 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
173 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
174 MGMT_STATUS_BUSY, /* Repeated Attempts */
175 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
176 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
177 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
178 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
179 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
180 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
181 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
182 MGMT_STATUS_FAILED, /* Unspecified Error */
183 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
184 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
185 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
186 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
187 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
188 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
189 MGMT_STATUS_FAILED, /* Unit Link Key Used */
190 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
191 MGMT_STATUS_TIMEOUT, /* Instant Passed */
192 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
193 MGMT_STATUS_FAILED, /* Transaction Collision */
194 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
195 MGMT_STATUS_REJECTED, /* QoS Rejected */
196 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
197 MGMT_STATUS_REJECTED, /* Insufficient Security */
198 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
199 MGMT_STATUS_BUSY, /* Role Switch Pending */
200 MGMT_STATUS_FAILED, /* Slot Violation */
201 MGMT_STATUS_FAILED, /* Role Switch Failed */
202 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
203 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
204 MGMT_STATUS_BUSY, /* Host Busy Pairing */
205 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
206 MGMT_STATUS_BUSY, /* Controller Busy */
207 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
208 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
209 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
210 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
211 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
212};
213
214static u8 mgmt_status(u8 hci_status)
215{
216 if (hci_status < ARRAY_SIZE(mgmt_status_table))
217 return mgmt_status_table[hci_status];
218
219 return MGMT_STATUS_FAILED;
220}
221
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700222static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
223 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700224{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700225 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
226 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700227}
228
Marcel Holtmann72000df2015-03-16 16:11:21 -0700229static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
230 u16 len, int flag, struct sock *skip_sk)
231{
232 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
233 flag, skip_sk);
234}
235
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700236static int mgmt_generic_event(u16 event, struct hci_dev *hdev, void *data,
237 u16 len, struct sock *skip_sk)
238{
239 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
240 HCI_MGMT_GENERIC_EVENTS, skip_sk);
241}
242
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200243static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
244 struct sock *skip_sk)
245{
246 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700247 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200248}
249
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300250static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
251 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200252{
253 struct mgmt_rp_read_version rp;
254
255 BT_DBG("sock %p", sk);
256
257 rp.version = MGMT_VERSION;
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700258 rp.revision = cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200259
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200260 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
261 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200262}
263
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300264static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
265 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200266{
267 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200268 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
269 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200270 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200271 size_t rp_size;
272 int i, err;
273
274 BT_DBG("sock %p", sk);
275
276 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
277
278 rp = kmalloc(rp_size, GFP_KERNEL);
279 if (!rp)
280 return -ENOMEM;
281
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700282 rp->num_commands = cpu_to_le16(num_commands);
283 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200284
285 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
286 put_unaligned_le16(mgmt_commands[i], opcode);
287
288 for (i = 0; i < num_events; i++, opcode++)
289 put_unaligned_le16(mgmt_events[i], opcode);
290
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200291 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
292 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200293 kfree(rp);
294
295 return err;
296}
297
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300298static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
299 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200300{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200301 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200302 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200303 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200304 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300305 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200306
307 BT_DBG("sock %p", sk);
308
309 read_lock(&hci_dev_list_lock);
310
311 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300312 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200313 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700314 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700315 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316 }
317
Johan Hedberga38528f2011-01-22 06:46:43 +0200318 rp_len = sizeof(*rp) + (2 * count);
319 rp = kmalloc(rp_len, GFP_ATOMIC);
320 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100321 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100323 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324
Johan Hedberg476e44c2012-10-19 20:10:46 +0300325 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200326 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700327 if (hci_dev_test_flag(d, HCI_SETUP) ||
328 hci_dev_test_flag(d, HCI_CONFIG) ||
329 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200330 continue;
331
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200332 /* Devices marked as raw-only are neither configured
333 * nor unconfigured controllers.
334 */
335 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700336 continue;
337
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200338 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700339 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700340 rp->index[count++] = cpu_to_le16(d->id);
341 BT_DBG("Added hci%u", d->id);
342 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200343 }
344
Johan Hedberg476e44c2012-10-19 20:10:46 +0300345 rp->num_controllers = cpu_to_le16(count);
346 rp_len = sizeof(*rp) + (2 * count);
347
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348 read_unlock(&hci_dev_list_lock);
349
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200350 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
351 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200352
Johan Hedberga38528f2011-01-22 06:46:43 +0200353 kfree(rp);
354
355 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356}
357
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200358static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
359 void *data, u16 data_len)
360{
361 struct mgmt_rp_read_unconf_index_list *rp;
362 struct hci_dev *d;
363 size_t rp_len;
364 u16 count;
365 int err;
366
367 BT_DBG("sock %p", sk);
368
369 read_lock(&hci_dev_list_lock);
370
371 count = 0;
372 list_for_each_entry(d, &hci_dev_list, list) {
373 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700374 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200375 count++;
376 }
377
378 rp_len = sizeof(*rp) + (2 * count);
379 rp = kmalloc(rp_len, GFP_ATOMIC);
380 if (!rp) {
381 read_unlock(&hci_dev_list_lock);
382 return -ENOMEM;
383 }
384
385 count = 0;
386 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700387 if (hci_dev_test_flag(d, HCI_SETUP) ||
388 hci_dev_test_flag(d, HCI_CONFIG) ||
389 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200390 continue;
391
392 /* Devices marked as raw-only are neither configured
393 * nor unconfigured controllers.
394 */
395 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
396 continue;
397
398 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700399 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200400 rp->index[count++] = cpu_to_le16(d->id);
401 BT_DBG("Added hci%u", d->id);
402 }
403 }
404
405 rp->num_controllers = cpu_to_le16(count);
406 rp_len = sizeof(*rp) + (2 * count);
407
408 read_unlock(&hci_dev_list_lock);
409
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200410 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
411 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200412
413 kfree(rp);
414
415 return err;
416}
417
Marcel Holtmann96f14742015-03-14 19:27:57 -0700418static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
419 void *data, u16 data_len)
420{
421 struct mgmt_rp_read_ext_index_list *rp;
422 struct hci_dev *d;
423 size_t rp_len;
424 u16 count;
425 int err;
426
427 BT_DBG("sock %p", sk);
428
429 read_lock(&hci_dev_list_lock);
430
431 count = 0;
432 list_for_each_entry(d, &hci_dev_list, list) {
433 if (d->dev_type == HCI_BREDR || d->dev_type == HCI_AMP)
434 count++;
435 }
436
437 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
438 rp = kmalloc(rp_len, GFP_ATOMIC);
439 if (!rp) {
440 read_unlock(&hci_dev_list_lock);
441 return -ENOMEM;
442 }
443
444 count = 0;
445 list_for_each_entry(d, &hci_dev_list, list) {
446 if (hci_dev_test_flag(d, HCI_SETUP) ||
447 hci_dev_test_flag(d, HCI_CONFIG) ||
448 hci_dev_test_flag(d, HCI_USER_CHANNEL))
449 continue;
450
451 /* Devices marked as raw-only are neither configured
452 * nor unconfigured controllers.
453 */
454 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
455 continue;
456
457 if (d->dev_type == HCI_BREDR) {
458 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
459 rp->entry[count].type = 0x01;
460 else
461 rp->entry[count].type = 0x00;
462 } else if (d->dev_type == HCI_AMP) {
463 rp->entry[count].type = 0x02;
464 } else {
465 continue;
466 }
467
468 rp->entry[count].bus = d->bus;
469 rp->entry[count++].index = cpu_to_le16(d->id);
470 BT_DBG("Added hci%u", d->id);
471 }
472
473 rp->num_controllers = cpu_to_le16(count);
474 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
475
476 read_unlock(&hci_dev_list_lock);
477
478 /* If this command is called at least once, then all the
479 * default index and unconfigured index events are disabled
480 * and from now on only extended index events are used.
481 */
482 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
483 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
484 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
485
486 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
487 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
488
489 kfree(rp);
490
491 return err;
492}
493
Marcel Holtmanndbece372014-07-04 18:11:55 +0200494static bool is_configured(struct hci_dev *hdev)
495{
496 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700497 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200498 return false;
499
500 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
501 !bacmp(&hdev->public_addr, BDADDR_ANY))
502 return false;
503
504 return true;
505}
506
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200507static __le32 get_missing_options(struct hci_dev *hdev)
508{
509 u32 options = 0;
510
Marcel Holtmanndbece372014-07-04 18:11:55 +0200511 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700512 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200513 options |= MGMT_OPTION_EXTERNAL_CONFIG;
514
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200515 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
516 !bacmp(&hdev->public_addr, BDADDR_ANY))
517 options |= MGMT_OPTION_PUBLIC_ADDRESS;
518
519 return cpu_to_le32(options);
520}
521
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200522static int new_options(struct hci_dev *hdev, struct sock *skip)
523{
524 __le32 options = get_missing_options(hdev);
525
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700526 return mgmt_generic_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
527 sizeof(options), skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200528}
529
Marcel Holtmanndbece372014-07-04 18:11:55 +0200530static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
531{
532 __le32 options = get_missing_options(hdev);
533
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200534 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
535 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200536}
537
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200538static int read_config_info(struct sock *sk, struct hci_dev *hdev,
539 void *data, u16 data_len)
540{
541 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200542 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200543
544 BT_DBG("sock %p %s", sk, hdev->name);
545
546 hci_dev_lock(hdev);
547
548 memset(&rp, 0, sizeof(rp));
549 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200550
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200551 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
552 options |= MGMT_OPTION_EXTERNAL_CONFIG;
553
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200554 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200555 options |= MGMT_OPTION_PUBLIC_ADDRESS;
556
557 rp.supported_options = cpu_to_le32(options);
558 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200559
560 hci_dev_unlock(hdev);
561
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200562 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
563 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200564}
565
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200566static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200567{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200568 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200569
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200570 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300571 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800572 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300573 settings |= MGMT_SETTING_CONNECTABLE;
574 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200575
Andre Guedesed3fa312012-07-24 15:03:46 -0300576 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500577 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
578 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200579 settings |= MGMT_SETTING_BREDR;
580 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700581
582 if (lmp_ssp_capable(hdev)) {
583 settings |= MGMT_SETTING_SSP;
584 settings |= MGMT_SETTING_HS;
585 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800586
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800587 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800588 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700589 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100590
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300591 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200592 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300593 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300594 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200595 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800596 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300597 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200598
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200599 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
600 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200601 settings |= MGMT_SETTING_CONFIGURATION;
602
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200603 return settings;
604}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200605
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200606static u32 get_current_settings(struct hci_dev *hdev)
607{
608 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200609
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200610 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100611 settings |= MGMT_SETTING_POWERED;
612
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700613 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200614 settings |= MGMT_SETTING_CONNECTABLE;
615
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700616 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500617 settings |= MGMT_SETTING_FAST_CONNECTABLE;
618
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700619 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200620 settings |= MGMT_SETTING_DISCOVERABLE;
621
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700622 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300623 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200624
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700625 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200626 settings |= MGMT_SETTING_BREDR;
627
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700628 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200629 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200630
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700631 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200632 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200633
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700634 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200635 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200636
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700637 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200638 settings |= MGMT_SETTING_HS;
639
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700640 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300641 settings |= MGMT_SETTING_ADVERTISING;
642
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700643 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800644 settings |= MGMT_SETTING_SECURE_CONN;
645
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700646 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800647 settings |= MGMT_SETTING_DEBUG_KEYS;
648
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700649 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200650 settings |= MGMT_SETTING_PRIVACY;
651
Marcel Holtmann93690c22015-03-06 10:11:21 -0800652 /* The current setting for static address has two purposes. The
653 * first is to indicate if the static address will be used and
654 * the second is to indicate if it is actually set.
655 *
656 * This means if the static address is not configured, this flag
657 * will never bet set. If the address is configured, then if the
658 * address is actually used decides if the flag is set or not.
659 *
660 * For single mode LE only controllers and dual-mode controllers
661 * with BR/EDR disabled, the existence of the static address will
662 * be evaluated.
663 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700664 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700665 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800666 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
667 if (bacmp(&hdev->static_addr, BDADDR_ANY))
668 settings |= MGMT_SETTING_STATIC_ADDRESS;
669 }
670
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200671 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200672}
673
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300674#define PNP_INFO_SVCLASS_ID 0x1200
675
Johan Hedberg213202e2013-01-27 00:31:33 +0200676static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
677{
678 u8 *ptr = data, *uuids_start = NULL;
679 struct bt_uuid *uuid;
680
681 if (len < 4)
682 return ptr;
683
684 list_for_each_entry(uuid, &hdev->uuids, list) {
685 u16 uuid16;
686
687 if (uuid->size != 16)
688 continue;
689
690 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
691 if (uuid16 < 0x1100)
692 continue;
693
694 if (uuid16 == PNP_INFO_SVCLASS_ID)
695 continue;
696
697 if (!uuids_start) {
698 uuids_start = ptr;
699 uuids_start[0] = 1;
700 uuids_start[1] = EIR_UUID16_ALL;
701 ptr += 2;
702 }
703
704 /* Stop if not enough space to put next UUID */
705 if ((ptr - data) + sizeof(u16) > len) {
706 uuids_start[1] = EIR_UUID16_SOME;
707 break;
708 }
709
710 *ptr++ = (uuid16 & 0x00ff);
711 *ptr++ = (uuid16 & 0xff00) >> 8;
712 uuids_start[0] += sizeof(uuid16);
713 }
714
715 return ptr;
716}
717
Johan Hedbergcdf19632013-01-27 00:31:34 +0200718static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
719{
720 u8 *ptr = data, *uuids_start = NULL;
721 struct bt_uuid *uuid;
722
723 if (len < 6)
724 return ptr;
725
726 list_for_each_entry(uuid, &hdev->uuids, list) {
727 if (uuid->size != 32)
728 continue;
729
730 if (!uuids_start) {
731 uuids_start = ptr;
732 uuids_start[0] = 1;
733 uuids_start[1] = EIR_UUID32_ALL;
734 ptr += 2;
735 }
736
737 /* Stop if not enough space to put next UUID */
738 if ((ptr - data) + sizeof(u32) > len) {
739 uuids_start[1] = EIR_UUID32_SOME;
740 break;
741 }
742
743 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
744 ptr += sizeof(u32);
745 uuids_start[0] += sizeof(u32);
746 }
747
748 return ptr;
749}
750
Johan Hedbergc00d5752013-01-27 00:31:35 +0200751static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
752{
753 u8 *ptr = data, *uuids_start = NULL;
754 struct bt_uuid *uuid;
755
756 if (len < 18)
757 return ptr;
758
759 list_for_each_entry(uuid, &hdev->uuids, list) {
760 if (uuid->size != 128)
761 continue;
762
763 if (!uuids_start) {
764 uuids_start = ptr;
765 uuids_start[0] = 1;
766 uuids_start[1] = EIR_UUID128_ALL;
767 ptr += 2;
768 }
769
770 /* Stop if not enough space to put next UUID */
771 if ((ptr - data) + 16 > len) {
772 uuids_start[1] = EIR_UUID128_SOME;
773 break;
774 }
775
776 memcpy(ptr, uuid->uuid, 16);
777 ptr += 16;
778 uuids_start[0] += 16;
779 }
780
781 return ptr;
782}
783
Johan Hedberg333ae952015-03-17 13:48:47 +0200784static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
785{
786 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
787}
788
Johan Hedberg333ae952015-03-17 13:48:47 +0200789static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
790 struct hci_dev *hdev,
791 const void *data)
792{
793 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
794}
795
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700796static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
797{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700798 u8 ad_len = 0;
799 size_t name_len;
800
801 name_len = strlen(hdev->dev_name);
802 if (name_len > 0) {
803 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
804
805 if (name_len > max_len) {
806 name_len = max_len;
807 ptr[1] = EIR_NAME_SHORT;
808 } else
809 ptr[1] = EIR_NAME_COMPLETE;
810
811 ptr[0] = name_len + 1;
812
813 memcpy(ptr + 2, hdev->dev_name, name_len);
814
815 ad_len += (name_len + 2);
816 ptr += (name_len + 2);
817 }
818
819 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700820}
821
822static void update_scan_rsp_data(struct hci_request *req)
823{
824 struct hci_dev *hdev = req->hdev;
825 struct hci_cp_le_set_scan_rsp_data cp;
826 u8 len;
827
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700828 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700829 return;
830
831 memset(&cp, 0, sizeof(cp));
832
833 len = create_scan_rsp_data(hdev, cp.data);
834
Johan Hedbergeb438b52013-10-16 15:31:07 +0300835 if (hdev->scan_rsp_data_len == len &&
836 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700837 return;
838
Johan Hedbergeb438b52013-10-16 15:31:07 +0300839 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
840 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700841
842 cp.length = len;
843
844 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
845}
846
Johan Hedberg9a43e252013-10-20 19:00:07 +0300847static u8 get_adv_discov_flags(struct hci_dev *hdev)
848{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200849 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300850
851 /* If there's a pending mgmt command the flags will not yet have
852 * their final values, so check for this first.
853 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200854 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300855 if (cmd) {
856 struct mgmt_mode *cp = cmd->param;
857 if (cp->val == 0x01)
858 return LE_AD_GENERAL;
859 else if (cp->val == 0x02)
860 return LE_AD_LIMITED;
861 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700862 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300863 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700864 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300865 return LE_AD_GENERAL;
866 }
867
868 return 0;
869}
870
Arman Uguray24b4f382015-03-23 15:57:12 -0700871static u8 create_default_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700872{
873 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700874
Johan Hedberg9a43e252013-10-20 19:00:07 +0300875 flags |= get_adv_discov_flags(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700876
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700877 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700878 flags |= LE_AD_NO_BREDR;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700879
880 if (flags) {
881 BT_DBG("adv flags 0x%02x", flags);
882
883 ptr[0] = 2;
884 ptr[1] = EIR_FLAGS;
885 ptr[2] = flags;
886
887 ad_len += 3;
888 ptr += 3;
889 }
890
891 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
892 ptr[0] = 2;
893 ptr[1] = EIR_TX_POWER;
894 ptr[2] = (u8) hdev->adv_tx_power;
895
896 ad_len += 3;
897 ptr += 3;
898 }
899
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700900 return ad_len;
901}
902
Arman Uguray24b4f382015-03-23 15:57:12 -0700903static u8 create_instance_adv_data(struct hci_dev *hdev, u8 *ptr)
904{
905 /* TODO: Set the appropriate entries based on advertising instance flags
906 * here once flags other than 0 are supported.
907 */
908 memcpy(ptr, hdev->adv_instance.adv_data,
909 hdev->adv_instance.adv_data_len);
910
911 return hdev->adv_instance.adv_data_len;
912}
913
914static void update_adv_data_for_instance(struct hci_request *req, u8 instance)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700915{
916 struct hci_dev *hdev = req->hdev;
917 struct hci_cp_le_set_adv_data cp;
918 u8 len;
919
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700920 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700921 return;
922
923 memset(&cp, 0, sizeof(cp));
924
Arman Uguray24b4f382015-03-23 15:57:12 -0700925 if (instance)
926 len = create_instance_adv_data(hdev, cp.data);
927 else
928 len = create_default_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700929
Arman Uguray24b4f382015-03-23 15:57:12 -0700930 /* There's nothing to do if the data hasn't changed */
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700931 if (hdev->adv_data_len == len &&
932 memcmp(cp.data, hdev->adv_data, len) == 0)
933 return;
934
935 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
936 hdev->adv_data_len = len;
937
938 cp.length = len;
939
940 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
941}
942
Arman Uguray24b4f382015-03-23 15:57:12 -0700943static void update_adv_data(struct hci_request *req)
944{
945 struct hci_dev *hdev = req->hdev;
946 u8 instance;
947
948 /* The "Set Advertising" setting supersedes the "Add Advertising"
949 * setting. Here we set the advertising data based on which
950 * setting was set. When neither apply, default to the global settings,
951 * represented by instance "0".
952 */
953 if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) &&
954 !hci_dev_test_flag(hdev, HCI_ADVERTISING))
955 instance = 0x01;
956 else
957 instance = 0x00;
958
959 update_adv_data_for_instance(req, instance);
960}
961
Johan Hedbergbc6d2d02014-07-10 12:09:08 +0300962int mgmt_update_adv_data(struct hci_dev *hdev)
963{
964 struct hci_request req;
965
966 hci_req_init(&req, hdev);
967 update_adv_data(&req);
968
969 return hci_req_run(&req, NULL);
970}
971
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300972static void create_eir(struct hci_dev *hdev, u8 *data)
973{
974 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300975 size_t name_len;
976
977 name_len = strlen(hdev->dev_name);
978
979 if (name_len > 0) {
980 /* EIR Data type */
981 if (name_len > 48) {
982 name_len = 48;
983 ptr[1] = EIR_NAME_SHORT;
984 } else
985 ptr[1] = EIR_NAME_COMPLETE;
986
987 /* EIR Data length */
988 ptr[0] = name_len + 1;
989
990 memcpy(ptr + 2, hdev->dev_name, name_len);
991
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300992 ptr += (name_len + 2);
993 }
994
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100995 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700996 ptr[0] = 2;
997 ptr[1] = EIR_TX_POWER;
998 ptr[2] = (u8) hdev->inq_tx_power;
999
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -07001000 ptr += 3;
1001 }
1002
Marcel Holtmann2b9be132012-03-11 19:32:12 -07001003 if (hdev->devid_source > 0) {
1004 ptr[0] = 9;
1005 ptr[1] = EIR_DEVICE_ID;
1006
1007 put_unaligned_le16(hdev->devid_source, ptr + 2);
1008 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
1009 put_unaligned_le16(hdev->devid_product, ptr + 6);
1010 put_unaligned_le16(hdev->devid_version, ptr + 8);
1011
Marcel Holtmann2b9be132012-03-11 19:32:12 -07001012 ptr += 10;
1013 }
1014
Johan Hedberg213202e2013-01-27 00:31:33 +02001015 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +02001016 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +02001017 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001018}
1019
Johan Hedberg890ea892013-03-15 17:06:52 -05001020static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001021{
Johan Hedberg890ea892013-03-15 17:06:52 -05001022 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001023 struct hci_cp_write_eir cp;
1024
Johan Hedberg504c8dc2012-02-23 13:30:41 +02001025 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001026 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +02001027
Johan Hedberg976eb202012-10-24 21:12:01 +03001028 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001029 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001030
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001031 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg890ea892013-03-15 17:06:52 -05001032 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001033
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001034 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -05001035 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001036
1037 memset(&cp, 0, sizeof(cp));
1038
1039 create_eir(hdev, cp.data);
1040
1041 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -05001042 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001043
1044 memcpy(hdev->eir, cp.data, sizeof(cp.data));
1045
Johan Hedberg890ea892013-03-15 17:06:52 -05001046 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001047}
1048
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001049static u8 get_service_classes(struct hci_dev *hdev)
1050{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -03001051 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001052 u8 val = 0;
1053
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -03001054 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001055 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001056
1057 return val;
1058}
1059
Johan Hedberg890ea892013-03-15 17:06:52 -05001060static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001061{
Johan Hedberg890ea892013-03-15 17:06:52 -05001062 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001063 u8 cod[3];
1064
1065 BT_DBG("%s", hdev->name);
1066
Johan Hedberg504c8dc2012-02-23 13:30:41 +02001067 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001068 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +02001069
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001070 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedbergf87ea1d2013-10-19 23:38:17 +03001071 return;
1072
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001073 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -05001074 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001075
1076 cod[0] = hdev->minor_class;
1077 cod[1] = hdev->major_class;
1078 cod[2] = get_service_classes(hdev);
1079
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001080 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Marcel Holtmann6acd7db2013-10-15 06:33:53 -07001081 cod[1] |= 0x20;
1082
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001083 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -05001084 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001085
Johan Hedberg890ea892013-03-15 17:06:52 -05001086 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001087}
1088
Johan Hedberga4858cb2014-02-25 19:56:31 +02001089static bool get_connectable(struct hci_dev *hdev)
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001090{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001091 struct mgmt_pending_cmd *cmd;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001092
1093 /* If there's a pending mgmt command the flag will not yet have
1094 * it's final value, so check for this first.
1095 */
Johan Hedberg333ae952015-03-17 13:48:47 +02001096 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001097 if (cmd) {
1098 struct mgmt_mode *cp = cmd->param;
Johan Hedberga4858cb2014-02-25 19:56:31 +02001099 return cp->val;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001100 }
1101
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001102 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001103}
1104
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001105static void disable_advertising(struct hci_request *req)
1106{
1107 u8 enable = 0x00;
1108
1109 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1110}
1111
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001112static void enable_advertising(struct hci_request *req)
1113{
1114 struct hci_dev *hdev = req->hdev;
1115 struct hci_cp_le_set_adv_param cp;
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001116 u8 own_addr_type, enable = 0x01;
Johan Hedberga4858cb2014-02-25 19:56:31 +02001117 bool connectable;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001118
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001119 if (hci_conn_num(hdev, LE_LINK) > 0)
1120 return;
1121
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001122 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001123 disable_advertising(req);
1124
Johan Hedberg5ce194c2014-07-08 15:07:49 +03001125 /* Clear the HCI_LE_ADV bit temporarily so that the
Johan Hedberg8d972502014-02-28 12:54:14 +02001126 * hci_update_random_address knows that it's safe to go ahead
1127 * and write a new random address. The flag will be set back on
1128 * as soon as the SET_ADV_ENABLE HCI command completes.
1129 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001130 hci_dev_clear_flag(hdev, HCI_LE_ADV);
Johan Hedberg8d972502014-02-28 12:54:14 +02001131
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001132 if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07001133 connectable = true;
1134 else
1135 connectable = get_connectable(hdev);
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001136
Johan Hedberga4858cb2014-02-25 19:56:31 +02001137 /* Set require_privacy to true only when non-connectable
1138 * advertising is used. In that case it is fine to use a
1139 * non-resolvable private address.
1140 */
1141 if (hci_update_random_address(req, !connectable, &own_addr_type) < 0)
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001142 return;
1143
Marcel Holtmann41c90c12014-02-23 20:25:55 -08001144 memset(&cp, 0, sizeof(cp));
Georg Lukas628531c2014-07-26 13:59:57 +02001145 cp.min_interval = cpu_to_le16(hdev->le_adv_min_interval);
1146 cp.max_interval = cpu_to_le16(hdev->le_adv_max_interval);
Johan Hedberga4858cb2014-02-25 19:56:31 +02001147 cp.type = connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001148 cp.own_address_type = own_addr_type;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001149 cp.channel_map = hdev->le_adv_channel_map;
1150
1151 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1152
1153 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1154}
1155
Johan Hedberg7d785252011-12-15 00:47:39 +02001156static void service_cache_off(struct work_struct *work)
1157{
1158 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001159 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -05001160 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +02001161
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001162 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +02001163 return;
1164
Johan Hedberg890ea892013-03-15 17:06:52 -05001165 hci_req_init(&req, hdev);
1166
Johan Hedberg7d785252011-12-15 00:47:39 +02001167 hci_dev_lock(hdev);
1168
Johan Hedberg890ea892013-03-15 17:06:52 -05001169 update_eir(&req);
1170 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001171
1172 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001173
1174 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +02001175}
1176
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001177static void rpa_expired(struct work_struct *work)
1178{
1179 struct hci_dev *hdev = container_of(work, struct hci_dev,
1180 rpa_expired.work);
1181 struct hci_request req;
1182
1183 BT_DBG("");
1184
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001185 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001186
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001187 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001188 return;
1189
1190 /* The generation of a new RPA and programming it into the
1191 * controller happens in the enable_advertising() function.
1192 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001193 hci_req_init(&req, hdev);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001194 enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001195 hci_req_run(&req, NULL);
1196}
1197
Johan Hedberg6a919082012-02-28 06:17:26 +02001198static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +02001199{
Marcel Holtmann238be782015-03-13 02:11:06 -07001200 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +02001201 return;
1202
Johan Hedberg4f87da82012-03-02 19:55:56 +02001203 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001204 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +02001205
Johan Hedberg4f87da82012-03-02 19:55:56 +02001206 /* Non-mgmt controlled devices get this bit set
1207 * implicitly so that pairing works for them, however
1208 * for mgmt we require user-space to explicitly enable
1209 * it
1210 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001211 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +02001212}
1213
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001214static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001215 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001216{
1217 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001218
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001219 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001220
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001221 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001222
Johan Hedberg03811012010-12-08 00:21:06 +02001223 memset(&rp, 0, sizeof(rp));
1224
Johan Hedberg03811012010-12-08 00:21:06 +02001225 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001226
1227 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001228 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001229
1230 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1231 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1232
1233 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +02001234
1235 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001236 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +02001237
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001238 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001239
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001240 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1241 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +02001242}
1243
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001244static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001245{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001246 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001247
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001248 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1249 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001250}
1251
Marcel Holtmann1904a852015-01-11 13:50:44 -08001252static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001253{
1254 BT_DBG("%s status 0x%02x", hdev->name, status);
1255
Johan Hedberga3172b72014-02-28 09:33:44 +02001256 if (hci_conn_count(hdev) == 0) {
1257 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001258 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001259 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001260}
1261
Johan Hedberg23a48092014-07-08 16:05:06 +03001262static bool hci_stop_discovery(struct hci_request *req)
Johan Hedberg21a60d32014-06-10 14:05:58 +03001263{
1264 struct hci_dev *hdev = req->hdev;
1265 struct hci_cp_remote_name_req_cancel cp;
1266 struct inquiry_entry *e;
1267
1268 switch (hdev->discovery.state) {
1269 case DISCOVERY_FINDING:
Jakub Pawlowski07d23342015-03-17 09:04:14 -07001270 if (test_bit(HCI_INQUIRY, &hdev->flags))
Johan Hedberg21a60d32014-06-10 14:05:58 +03001271 hci_req_add(req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
Jakub Pawlowski07d23342015-03-17 09:04:14 -07001272
1273 if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
Johan Hedberg21a60d32014-06-10 14:05:58 +03001274 cancel_delayed_work(&hdev->le_scan_disable);
1275 hci_req_add_le_scan_disable(req);
1276 }
1277
Johan Hedberg23a48092014-07-08 16:05:06 +03001278 return true;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001279
1280 case DISCOVERY_RESOLVING:
1281 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
1282 NAME_PENDING);
1283 if (!e)
Johan Hedberg23a48092014-07-08 16:05:06 +03001284 break;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001285
1286 bacpy(&cp.bdaddr, &e->data.bdaddr);
1287 hci_req_add(req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
1288 &cp);
1289
Johan Hedberg23a48092014-07-08 16:05:06 +03001290 return true;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001291
1292 default:
1293 /* Passive scanning */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001294 if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
Johan Hedberg21a60d32014-06-10 14:05:58 +03001295 hci_req_add_le_scan_disable(req);
Johan Hedberg23a48092014-07-08 16:05:06 +03001296 return true;
1297 }
1298
Johan Hedberg21a60d32014-06-10 14:05:58 +03001299 break;
1300 }
Johan Hedberg23a48092014-07-08 16:05:06 +03001301
1302 return false;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001303}
1304
Johan Hedberg8b064a32014-02-24 14:52:22 +02001305static int clean_up_hci_state(struct hci_dev *hdev)
1306{
1307 struct hci_request req;
1308 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001309 bool discov_stopped;
1310 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001311
1312 hci_req_init(&req, hdev);
1313
1314 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1315 test_bit(HCI_PSCAN, &hdev->flags)) {
1316 u8 scan = 0x00;
1317 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1318 }
1319
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001320 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedberg8b064a32014-02-24 14:52:22 +02001321 disable_advertising(&req);
1322
Johan Hedberg23a48092014-07-08 16:05:06 +03001323 discov_stopped = hci_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001324
1325 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
1326 struct hci_cp_disconnect dc;
Johan Hedbergc9910d02014-02-27 14:35:12 +02001327 struct hci_cp_reject_conn_req rej;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001328
Johan Hedbergc9910d02014-02-27 14:35:12 +02001329 switch (conn->state) {
1330 case BT_CONNECTED:
1331 case BT_CONFIG:
1332 dc.handle = cpu_to_le16(conn->handle);
1333 dc.reason = 0x15; /* Terminated due to Power Off */
1334 hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1335 break;
1336 case BT_CONNECT:
1337 if (conn->type == LE_LINK)
1338 hci_req_add(&req, HCI_OP_LE_CREATE_CONN_CANCEL,
1339 0, NULL);
1340 else if (conn->type == ACL_LINK)
1341 hci_req_add(&req, HCI_OP_CREATE_CONN_CANCEL,
1342 6, &conn->dst);
1343 break;
1344 case BT_CONNECT2:
1345 bacpy(&rej.bdaddr, &conn->dst);
1346 rej.reason = 0x15; /* Terminated due to Power Off */
1347 if (conn->type == ACL_LINK)
1348 hci_req_add(&req, HCI_OP_REJECT_CONN_REQ,
1349 sizeof(rej), &rej);
1350 else if (conn->type == SCO_LINK)
1351 hci_req_add(&req, HCI_OP_REJECT_SYNC_CONN_REQ,
1352 sizeof(rej), &rej);
1353 break;
1354 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001355 }
1356
Johan Hedberg23a48092014-07-08 16:05:06 +03001357 err = hci_req_run(&req, clean_up_hci_complete);
1358 if (!err && discov_stopped)
1359 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1360
1361 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001362}
1363
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001364static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001365 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001366{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001367 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001368 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001369 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001370
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001371 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001372
Johan Hedberga7e80f22013-01-09 16:05:19 +02001373 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001374 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1375 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001376
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001377 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001378
Johan Hedberg333ae952015-03-17 13:48:47 +02001379 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001380 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1381 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001382 goto failed;
1383 }
1384
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001385 if (hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001386 cancel_delayed_work(&hdev->power_off);
1387
1388 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +02001389 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
1390 data, len);
1391 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001392 goto failed;
1393 }
1394 }
1395
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001396 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001397 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001398 goto failed;
1399 }
1400
Johan Hedberg03811012010-12-08 00:21:06 +02001401 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1402 if (!cmd) {
1403 err = -ENOMEM;
1404 goto failed;
1405 }
1406
Johan Hedberg8b064a32014-02-24 14:52:22 +02001407 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001408 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001409 err = 0;
1410 } else {
1411 /* Disconnect connections, stop scans, etc */
1412 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001413 if (!err)
1414 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1415 HCI_POWER_OFF_TIMEOUT);
Johan Hedberg03811012010-12-08 00:21:06 +02001416
Johan Hedberg8b064a32014-02-24 14:52:22 +02001417 /* ENODATA means there were no HCI commands queued */
1418 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001419 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001420 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1421 err = 0;
1422 }
1423 }
Johan Hedberg03811012010-12-08 00:21:06 +02001424
1425failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001426 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001427 return err;
1428}
1429
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001430static int new_settings(struct hci_dev *hdev, struct sock *skip)
1431{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001432 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001433
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001434 return mgmt_generic_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1435 sizeof(ev), skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001436}
1437
Johan Hedberg91a668b2014-07-09 13:28:26 +03001438int mgmt_new_settings(struct hci_dev *hdev)
1439{
1440 return new_settings(hdev, NULL);
1441}
1442
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001443struct cmd_lookup {
1444 struct sock *sk;
1445 struct hci_dev *hdev;
1446 u8 mgmt_status;
1447};
1448
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001449static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001450{
1451 struct cmd_lookup *match = data;
1452
1453 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1454
1455 list_del(&cmd->list);
1456
1457 if (match->sk == NULL) {
1458 match->sk = cmd->sk;
1459 sock_hold(match->sk);
1460 }
1461
1462 mgmt_pending_free(cmd);
1463}
1464
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001465static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001466{
1467 u8 *status = data;
1468
Johan Hedberga69e8372015-03-06 21:08:53 +02001469 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001470 mgmt_pending_remove(cmd);
1471}
1472
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001473static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001474{
1475 if (cmd->cmd_complete) {
1476 u8 *status = data;
1477
1478 cmd->cmd_complete(cmd, *status);
1479 mgmt_pending_remove(cmd);
1480
1481 return;
1482 }
1483
1484 cmd_status_rsp(cmd, data);
1485}
1486
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001487static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001488{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001489 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1490 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001491}
1492
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001493static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001494{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001495 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1496 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001497}
1498
Johan Hedberge6fe7982013-10-02 15:45:22 +03001499static u8 mgmt_bredr_support(struct hci_dev *hdev)
1500{
1501 if (!lmp_bredr_capable(hdev))
1502 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001503 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001504 return MGMT_STATUS_REJECTED;
1505 else
1506 return MGMT_STATUS_SUCCESS;
1507}
1508
1509static u8 mgmt_le_support(struct hci_dev *hdev)
1510{
1511 if (!lmp_le_capable(hdev))
1512 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001513 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001514 return MGMT_STATUS_REJECTED;
1515 else
1516 return MGMT_STATUS_SUCCESS;
1517}
1518
Marcel Holtmann1904a852015-01-11 13:50:44 -08001519static void set_discoverable_complete(struct hci_dev *hdev, u8 status,
1520 u16 opcode)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001521{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001522 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001523 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001524 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001525 bool changed;
1526
1527 BT_DBG("status 0x%02x", status);
1528
1529 hci_dev_lock(hdev);
1530
Johan Hedberg333ae952015-03-17 13:48:47 +02001531 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001532 if (!cmd)
1533 goto unlock;
1534
1535 if (status) {
1536 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001537 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001538 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001539 goto remove_cmd;
1540 }
1541
1542 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001543 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001544 changed = !hci_dev_test_and_set_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001545
1546 if (hdev->discov_timeout > 0) {
1547 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1548 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1549 to);
1550 }
1551 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001552 changed = hci_dev_test_and_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001553 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001554
1555 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1556
1557 if (changed)
1558 new_settings(hdev, cmd->sk);
1559
Marcel Holtmann970ba522013-10-15 06:33:57 -07001560 /* When the discoverable mode gets changed, make sure
1561 * that class of device has the limited discoverable
Johan Hedberg432df052014-08-01 11:13:31 +03001562 * bit correctly set. Also update page scan based on whitelist
1563 * entries.
Marcel Holtmann970ba522013-10-15 06:33:57 -07001564 */
1565 hci_req_init(&req, hdev);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001566 __hci_update_page_scan(&req);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001567 update_class(&req);
1568 hci_req_run(&req, NULL);
1569
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001570remove_cmd:
1571 mgmt_pending_remove(cmd);
1572
1573unlock:
1574 hci_dev_unlock(hdev);
1575}
1576
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001577static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001578 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001579{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001580 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001581 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001582 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001583 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001584 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001585 int err;
Johan Hedberge41d8b42010-12-13 21:07:03 +02001586
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001587 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001588
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001589 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1590 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001591 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1592 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001593
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001594 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001595 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1596 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001597
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001598 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001599
1600 /* Disabling discoverable requires that no timeout is set,
1601 * and enabling limited discoverable requires a timeout.
1602 */
1603 if ((cp->val == 0x00 && timeout > 0) ||
1604 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001605 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1606 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001607
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001608 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001609
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001610 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001611 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1612 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001613 goto failed;
1614 }
1615
Johan Hedberg333ae952015-03-17 13:48:47 +02001616 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1617 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001618 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1619 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001620 goto failed;
1621 }
1622
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001623 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001624 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1625 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001626 goto failed;
1627 }
1628
1629 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001630 bool changed = false;
1631
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001632 /* Setting limited discoverable when powered off is
1633 * not a valid operation since it requires a timeout
1634 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1635 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001636 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001637 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001638 changed = true;
1639 }
1640
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001641 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001642 if (err < 0)
1643 goto failed;
1644
1645 if (changed)
1646 err = new_settings(hdev, sk);
1647
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001648 goto failed;
1649 }
1650
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001651 /* If the current mode is the same, then just update the timeout
1652 * value with the new value. And if only the timeout gets updated,
1653 * then no need for any HCI transactions.
1654 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001655 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1656 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1657 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001658 cancel_delayed_work(&hdev->discov_off);
1659 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001660
Marcel Holtmann36261542013-10-15 08:28:51 -07001661 if (cp->val && hdev->discov_timeout > 0) {
1662 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001663 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001664 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001665 }
1666
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001667 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001668 goto failed;
1669 }
1670
1671 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1672 if (!cmd) {
1673 err = -ENOMEM;
1674 goto failed;
1675 }
1676
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001677 /* Cancel any potential discoverable timeout that might be
1678 * still active and store new timeout value. The arming of
1679 * the timeout happens in the complete handler.
1680 */
1681 cancel_delayed_work(&hdev->discov_off);
1682 hdev->discov_timeout = timeout;
1683
Johan Hedbergb456f872013-10-19 23:38:22 +03001684 /* Limited discoverable mode */
1685 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001686 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001687 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001688 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001689
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001690 hci_req_init(&req, hdev);
1691
Johan Hedberg9a43e252013-10-20 19:00:07 +03001692 /* The procedure for LE-only controllers is much simpler - just
1693 * update the advertising data.
1694 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001695 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg9a43e252013-10-20 19:00:07 +03001696 goto update_ad;
1697
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001698 scan = SCAN_PAGE;
1699
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001700 if (cp->val) {
1701 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001702
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001703 if (cp->val == 0x02) {
1704 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001705 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001706 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1707 hci_cp.iac_lap[1] = 0x8b;
1708 hci_cp.iac_lap[2] = 0x9e;
1709 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1710 hci_cp.iac_lap[4] = 0x8b;
1711 hci_cp.iac_lap[5] = 0x9e;
1712 } else {
1713 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001714 hci_cp.num_iac = 1;
1715 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1716 hci_cp.iac_lap[1] = 0x8b;
1717 hci_cp.iac_lap[2] = 0x9e;
1718 }
1719
1720 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1721 (hci_cp.num_iac * 3) + 1, &hci_cp);
1722
1723 scan |= SCAN_INQUIRY;
1724 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001725 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001726 }
1727
1728 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001729
Johan Hedberg9a43e252013-10-20 19:00:07 +03001730update_ad:
1731 update_adv_data(&req);
1732
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001733 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001734 if (err < 0)
1735 mgmt_pending_remove(cmd);
1736
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001737failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001738 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001739 return err;
1740}
1741
Johan Hedberg406d7802013-03-15 17:07:09 -05001742static void write_fast_connectable(struct hci_request *req, bool enable)
1743{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001744 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001745 struct hci_cp_write_page_scan_activity acp;
1746 u8 type;
1747
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001748 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg547003b2013-10-21 16:51:53 +03001749 return;
1750
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001751 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1752 return;
1753
Johan Hedberg406d7802013-03-15 17:07:09 -05001754 if (enable) {
1755 type = PAGE_SCAN_TYPE_INTERLACED;
1756
1757 /* 160 msec page scan interval */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001758 acp.interval = cpu_to_le16(0x0100);
Johan Hedberg406d7802013-03-15 17:07:09 -05001759 } else {
1760 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1761
1762 /* default 1.28 sec page scan */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001763 acp.interval = cpu_to_le16(0x0800);
Johan Hedberg406d7802013-03-15 17:07:09 -05001764 }
1765
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001766 acp.window = cpu_to_le16(0x0012);
Johan Hedberg406d7802013-03-15 17:07:09 -05001767
Johan Hedbergbd98b992013-03-15 17:07:13 -05001768 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1769 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1770 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1771 sizeof(acp), &acp);
1772
1773 if (hdev->page_scan_type != type)
1774 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001775}
1776
Marcel Holtmann1904a852015-01-11 13:50:44 -08001777static void set_connectable_complete(struct hci_dev *hdev, u8 status,
1778 u16 opcode)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001779{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001780 struct mgmt_pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001781 struct mgmt_mode *cp;
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001782 bool conn_changed, discov_changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001783
1784 BT_DBG("status 0x%02x", status);
1785
1786 hci_dev_lock(hdev);
1787
Johan Hedberg333ae952015-03-17 13:48:47 +02001788 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001789 if (!cmd)
1790 goto unlock;
1791
Johan Hedberg37438c12013-10-14 16:20:05 +03001792 if (status) {
1793 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001794 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001795 goto remove_cmd;
1796 }
1797
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001798 cp = cmd->param;
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001799 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001800 conn_changed = !hci_dev_test_and_set_flag(hdev,
1801 HCI_CONNECTABLE);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001802 discov_changed = false;
1803 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001804 conn_changed = hci_dev_test_and_clear_flag(hdev,
1805 HCI_CONNECTABLE);
1806 discov_changed = hci_dev_test_and_clear_flag(hdev,
1807 HCI_DISCOVERABLE);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001808 }
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001809
Johan Hedberg2b76f452013-03-15 17:07:04 -05001810 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1811
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001812 if (conn_changed || discov_changed) {
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001813 new_settings(hdev, cmd->sk);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001814 hci_update_page_scan(hdev);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001815 if (discov_changed)
1816 mgmt_update_adv_data(hdev);
Johan Hedberg2b7be332014-07-07 14:40:22 +03001817 hci_update_background_scan(hdev);
1818 }
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001819
Johan Hedberg37438c12013-10-14 16:20:05 +03001820remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001821 mgmt_pending_remove(cmd);
1822
1823unlock:
1824 hci_dev_unlock(hdev);
1825}
1826
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001827static int set_connectable_update_settings(struct hci_dev *hdev,
1828 struct sock *sk, u8 val)
1829{
1830 bool changed = false;
1831 int err;
1832
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001833 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001834 changed = true;
1835
1836 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001837 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001838 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001839 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1840 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001841 }
1842
1843 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1844 if (err < 0)
1845 return err;
1846
Johan Hedberg562064e2014-07-08 16:35:34 +03001847 if (changed) {
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001848 hci_update_page_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001849 hci_update_background_scan(hdev);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001850 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001851 }
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001852
1853 return 0;
1854}
1855
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001856static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001857 u16 len)
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001858{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001859 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001860 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001861 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001862 u8 scan;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001863 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001864
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001865 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001866
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001867 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1868 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001869 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1870 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001871
Johan Hedberga7e80f22013-01-09 16:05:19 +02001872 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001873 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1874 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001875
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001876 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001877
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001878 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001879 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001880 goto failed;
1881 }
1882
Johan Hedberg333ae952015-03-17 13:48:47 +02001883 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1884 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001885 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1886 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001887 goto failed;
1888 }
1889
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001890 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1891 if (!cmd) {
1892 err = -ENOMEM;
1893 goto failed;
1894 }
1895
Johan Hedberg2b76f452013-03-15 17:07:04 -05001896 hci_req_init(&req, hdev);
1897
Johan Hedberg9a43e252013-10-20 19:00:07 +03001898 /* If BR/EDR is not enabled and we disable advertising as a
1899 * by-product of disabling connectable, we need to update the
1900 * advertising flags.
1901 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001902 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg9a43e252013-10-20 19:00:07 +03001903 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001904 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1905 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg9a43e252013-10-20 19:00:07 +03001906 }
1907 update_adv_data(&req);
1908 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001909 if (cp->val) {
1910 scan = SCAN_PAGE;
1911 } else {
Johan Hedberg3bd27242014-07-28 20:53:58 +03001912 /* If we don't have any whitelist entries just
1913 * disable all scanning. If there are entries
1914 * and we had both page and inquiry scanning
1915 * enabled then fall back to only page scanning.
1916 * Otherwise no changes are needed.
1917 */
1918 if (list_empty(&hdev->whitelist))
1919 scan = SCAN_DISABLED;
1920 else if (test_bit(HCI_ISCAN, &hdev->flags))
1921 scan = SCAN_PAGE;
1922 else
1923 goto no_scan_update;
Johan Hedberg9b742462013-10-14 16:20:03 +03001924
1925 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001926 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001927 cancel_delayed_work(&hdev->discov_off);
1928 }
1929
1930 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1931 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001932
Johan Hedberg3bd27242014-07-28 20:53:58 +03001933no_scan_update:
Johan Hedberge8b12022014-07-10 10:51:27 +03001934 /* Update the advertising parameters if necessary */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001935 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001936 enable_advertising(&req);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001937
Johan Hedberg2b76f452013-03-15 17:07:04 -05001938 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001939 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001940 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001941 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03001942 err = set_connectable_update_settings(hdev, sk,
1943 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03001944 goto failed;
1945 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001946
1947failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001948 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001949 return err;
1950}
1951
Johan Hedbergb2939472014-07-30 09:22:23 +03001952static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001953 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001954{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001955 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001956 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001957 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001958
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001959 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001960
Johan Hedberga7e80f22013-01-09 16:05:19 +02001961 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001962 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1963 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001964
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001965 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001966
1967 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001968 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001969 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001970 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001971
Johan Hedbergb2939472014-07-30 09:22:23 +03001972 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001973 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001974 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001975
Marcel Holtmann55594352013-10-06 16:11:57 -07001976 if (changed)
1977 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001978
Marcel Holtmann55594352013-10-06 16:11:57 -07001979unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001980 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001981 return err;
1982}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001983
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001984static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1985 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001986{
1987 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001988 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001989 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001990 int err;
1991
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001992 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001993
Johan Hedberge6fe7982013-10-02 15:45:22 +03001994 status = mgmt_bredr_support(hdev);
1995 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001996 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1997 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001998
Johan Hedberga7e80f22013-01-09 16:05:19 +02001999 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002000 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2001 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002002
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002003 hci_dev_lock(hdev);
2004
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002005 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02002006 bool changed = false;
2007
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002008 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07002009 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02002010 changed = true;
2011 }
2012
2013 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
2014 if (err < 0)
2015 goto failed;
2016
2017 if (changed)
2018 err = new_settings(hdev, sk);
2019
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002020 goto failed;
2021 }
2022
Johan Hedberg333ae952015-03-17 13:48:47 +02002023 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002024 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2025 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002026 goto failed;
2027 }
2028
2029 val = !!cp->val;
2030
2031 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
2032 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
2033 goto failed;
2034 }
2035
2036 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
2037 if (!cmd) {
2038 err = -ENOMEM;
2039 goto failed;
2040 }
2041
2042 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
2043 if (err < 0) {
2044 mgmt_pending_remove(cmd);
2045 goto failed;
2046 }
2047
2048failed:
2049 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002050 return err;
2051}
2052
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002053static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002054{
2055 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002056 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07002057 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002058 int err;
2059
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002060 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002061
Marcel Holtmanncdba5282013-10-02 21:31:52 -07002062 status = mgmt_bredr_support(hdev);
2063 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002064 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07002065
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002066 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002067 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2068 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002069
Johan Hedberga7e80f22013-01-09 16:05:19 +02002070 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002071 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2072 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002073
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002074 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02002075
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002076 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002077 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02002078
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002079 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07002080 changed = !hci_dev_test_and_set_flag(hdev,
2081 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002082 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002083 changed = hci_dev_test_and_clear_flag(hdev,
2084 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002085 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002086 changed = hci_dev_test_and_clear_flag(hdev,
2087 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002088 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002089 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02002090 }
2091
2092 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
2093 if (err < 0)
2094 goto failed;
2095
2096 if (changed)
2097 err = new_settings(hdev, sk);
2098
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002099 goto failed;
2100 }
2101
Johan Hedberg333ae952015-03-17 13:48:47 +02002102 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002103 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2104 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002105 goto failed;
2106 }
2107
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002108 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002109 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
2110 goto failed;
2111 }
2112
2113 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
2114 if (!cmd) {
2115 err = -ENOMEM;
2116 goto failed;
2117 }
2118
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002119 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03002120 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
2121 sizeof(cp->val), &cp->val);
2122
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07002123 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002124 if (err < 0) {
2125 mgmt_pending_remove(cmd);
2126 goto failed;
2127 }
2128
2129failed:
2130 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002131 return err;
2132}
2133
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002134static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002135{
2136 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07002137 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03002138 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07002139 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002140
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002141 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002142
Johan Hedberge6fe7982013-10-02 15:45:22 +03002143 status = mgmt_bredr_support(hdev);
2144 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002145 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002146
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002147 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002148 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2149 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002150
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002151 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02002152 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2153 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002154
Johan Hedberga7e80f22013-01-09 16:05:19 +02002155 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002156 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2157 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002158
Marcel Holtmannee392692013-10-01 22:59:23 -07002159 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002160
Johan Hedberg333ae952015-03-17 13:48:47 +02002161 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002162 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2163 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02002164 goto unlock;
2165 }
2166
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002167 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07002168 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002169 } else {
2170 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002171 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2172 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002173 goto unlock;
2174 }
2175
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002176 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002177 }
Marcel Holtmannee392692013-10-01 22:59:23 -07002178
2179 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
2180 if (err < 0)
2181 goto unlock;
2182
2183 if (changed)
2184 err = new_settings(hdev, sk);
2185
2186unlock:
2187 hci_dev_unlock(hdev);
2188 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002189}
2190
Marcel Holtmann1904a852015-01-11 13:50:44 -08002191static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002192{
2193 struct cmd_lookup match = { NULL, hdev };
2194
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302195 hci_dev_lock(hdev);
2196
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002197 if (status) {
2198 u8 mgmt_err = mgmt_status(status);
2199
2200 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
2201 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302202 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002203 }
2204
2205 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
2206
2207 new_settings(hdev, match.sk);
2208
2209 if (match.sk)
2210 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002211
2212 /* Make sure the controller has a good default for
2213 * advertising data. Restrict the update to when LE
2214 * has actually been enabled. During power on, the
2215 * update in powered_update_hci will take care of it.
2216 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002217 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002218 struct hci_request req;
2219
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002220 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07002221 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07002222 update_scan_rsp_data(&req);
Johan Hedberg2cf22212014-12-19 22:26:00 +02002223 __hci_update_background_scan(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002224 hci_req_run(&req, NULL);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002225 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302226
2227unlock:
2228 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002229}
2230
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002231static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002232{
2233 struct mgmt_mode *cp = data;
2234 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002235 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002236 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002237 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002238 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002239
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002240 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002241
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002242 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002243 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2244 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002245
Johan Hedberga7e80f22013-01-09 16:05:19 +02002246 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002247 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2248 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002249
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07002250 /* Bluetooth single mode LE only controllers or dual-mode
2251 * controllers configured as LE only devices, do not allow
2252 * switching LE off. These have either LE enabled explicitly
2253 * or BR/EDR has been previously switched off.
2254 *
2255 * When trying to enable an already enabled LE, then gracefully
2256 * send a positive response. Trying to disable it however will
2257 * result into rejection.
2258 */
2259 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
2260 if (cp->val == 0x01)
2261 return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
2262
Johan Hedberga69e8372015-03-06 21:08:53 +02002263 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2264 MGMT_STATUS_REJECTED);
Marcel Holtmanne7844ee2015-03-18 16:15:07 -07002265 }
Johan Hedbergc73eee92013-04-19 18:35:21 +03002266
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002267 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002268
2269 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02002270 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002271
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002272 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02002273 bool changed = false;
2274
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002275 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07002276 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002277 changed = true;
2278 }
2279
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002280 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002281 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03002282 changed = true;
2283 }
2284
Johan Hedberg06199cf2012-02-22 16:37:11 +02002285 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
2286 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08002287 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002288
2289 if (changed)
2290 err = new_settings(hdev, sk);
2291
Johan Hedberg1de028c2012-02-29 19:55:35 -08002292 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002293 }
2294
Johan Hedberg333ae952015-03-17 13:48:47 +02002295 if (pending_find(MGMT_OP_SET_LE, hdev) ||
2296 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002297 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2298 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002299 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002300 }
2301
2302 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
2303 if (!cmd) {
2304 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08002305 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002306 }
2307
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002308 hci_req_init(&req, hdev);
2309
Johan Hedberg06199cf2012-02-22 16:37:11 +02002310 memset(&hci_cp, 0, sizeof(hci_cp));
2311
2312 if (val) {
2313 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02002314 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002315 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002316 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002317 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002318 }
2319
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002320 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
2321 &hci_cp);
2322
2323 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05302324 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002325 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002326
Johan Hedberg1de028c2012-02-29 19:55:35 -08002327unlock:
2328 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002329 return err;
2330}
2331
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002332/* This is a helper function to test for pending mgmt commands that can
2333 * cause CoD or EIR HCI commands. We can only allow one such pending
2334 * mgmt command at a time since otherwise we cannot easily track what
2335 * the current values are, will be, and based on that calculate if a new
2336 * HCI command needs to be sent and if yes with what value.
2337 */
2338static bool pending_eir_or_class(struct hci_dev *hdev)
2339{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002340 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002341
2342 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2343 switch (cmd->opcode) {
2344 case MGMT_OP_ADD_UUID:
2345 case MGMT_OP_REMOVE_UUID:
2346 case MGMT_OP_SET_DEV_CLASS:
2347 case MGMT_OP_SET_POWERED:
2348 return true;
2349 }
2350 }
2351
2352 return false;
2353}
2354
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002355static const u8 bluetooth_base_uuid[] = {
2356 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2357 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2358};
2359
2360static u8 get_uuid_size(const u8 *uuid)
2361{
2362 u32 val;
2363
2364 if (memcmp(uuid, bluetooth_base_uuid, 12))
2365 return 128;
2366
2367 val = get_unaligned_le32(&uuid[12]);
2368 if (val > 0xffff)
2369 return 32;
2370
2371 return 16;
2372}
2373
Johan Hedberg92da6092013-03-15 17:06:55 -05002374static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2375{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002376 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002377
2378 hci_dev_lock(hdev);
2379
Johan Hedberg333ae952015-03-17 13:48:47 +02002380 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002381 if (!cmd)
2382 goto unlock;
2383
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002384 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2385 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002386
2387 mgmt_pending_remove(cmd);
2388
2389unlock:
2390 hci_dev_unlock(hdev);
2391}
2392
Marcel Holtmann1904a852015-01-11 13:50:44 -08002393static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002394{
2395 BT_DBG("status 0x%02x", status);
2396
2397 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2398}
2399
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002400static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002401{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002402 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002403 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002404 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002405 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002406 int err;
2407
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002408 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002409
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002410 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002411
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002412 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002413 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2414 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002415 goto failed;
2416 }
2417
Andre Guedes92c4c202012-06-07 19:05:44 -03002418 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002419 if (!uuid) {
2420 err = -ENOMEM;
2421 goto failed;
2422 }
2423
2424 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002425 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002426 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002427
Johan Hedbergde66aa62013-01-27 00:31:27 +02002428 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002429
Johan Hedberg890ea892013-03-15 17:06:52 -05002430 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002431
Johan Hedberg890ea892013-03-15 17:06:52 -05002432 update_class(&req);
2433 update_eir(&req);
2434
Johan Hedberg92da6092013-03-15 17:06:55 -05002435 err = hci_req_run(&req, add_uuid_complete);
2436 if (err < 0) {
2437 if (err != -ENODATA)
2438 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002439
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002440 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2441 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002442 goto failed;
2443 }
2444
2445 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002446 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002447 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002448 goto failed;
2449 }
2450
2451 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002452
2453failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002454 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002455 return err;
2456}
2457
Johan Hedberg24b78d02012-02-23 23:24:30 +02002458static bool enable_service_cache(struct hci_dev *hdev)
2459{
2460 if (!hdev_is_powered(hdev))
2461 return false;
2462
Marcel Holtmann238be782015-03-13 02:11:06 -07002463 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002464 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2465 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002466 return true;
2467 }
2468
2469 return false;
2470}
2471
Marcel Holtmann1904a852015-01-11 13:50:44 -08002472static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002473{
2474 BT_DBG("status 0x%02x", status);
2475
2476 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2477}
2478
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002479static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002480 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002481{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002482 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002483 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002484 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002485 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 -05002486 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002487 int err, found;
2488
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002489 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002490
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002491 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002492
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002493 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002494 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2495 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002496 goto unlock;
2497 }
2498
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002499 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002500 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002501
Johan Hedberg24b78d02012-02-23 23:24:30 +02002502 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002503 err = mgmt_cmd_complete(sk, hdev->id,
2504 MGMT_OP_REMOVE_UUID,
2505 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002506 goto unlock;
2507 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002508
Johan Hedberg9246a862012-02-23 21:33:16 +02002509 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002510 }
2511
2512 found = 0;
2513
Johan Hedberg056341c2013-01-27 00:31:30 +02002514 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002515 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2516 continue;
2517
2518 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002519 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002520 found++;
2521 }
2522
2523 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002524 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2525 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002526 goto unlock;
2527 }
2528
Johan Hedberg9246a862012-02-23 21:33:16 +02002529update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002530 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002531
Johan Hedberg890ea892013-03-15 17:06:52 -05002532 update_class(&req);
2533 update_eir(&req);
2534
Johan Hedberg92da6092013-03-15 17:06:55 -05002535 err = hci_req_run(&req, remove_uuid_complete);
2536 if (err < 0) {
2537 if (err != -ENODATA)
2538 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002539
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002540 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2541 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002542 goto unlock;
2543 }
2544
2545 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002546 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002547 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002548 goto unlock;
2549 }
2550
2551 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002552
2553unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002554 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002555 return err;
2556}
2557
Marcel Holtmann1904a852015-01-11 13:50:44 -08002558static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002559{
2560 BT_DBG("status 0x%02x", status);
2561
2562 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2563}
2564
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002565static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002566 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002567{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002568 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002569 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002570 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002571 int err;
2572
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002573 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002574
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002575 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002576 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2577 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002578
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002579 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002580
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002581 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002582 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2583 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002584 goto unlock;
2585 }
2586
2587 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002588 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2589 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002590 goto unlock;
2591 }
2592
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002593 hdev->major_class = cp->major;
2594 hdev->minor_class = cp->minor;
2595
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002596 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002597 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2598 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002599 goto unlock;
2600 }
2601
Johan Hedberg890ea892013-03-15 17:06:52 -05002602 hci_req_init(&req, hdev);
2603
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002604 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002605 hci_dev_unlock(hdev);
2606 cancel_delayed_work_sync(&hdev->service_cache);
2607 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002608 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002609 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002610
Johan Hedberg890ea892013-03-15 17:06:52 -05002611 update_class(&req);
2612
Johan Hedberg92da6092013-03-15 17:06:55 -05002613 err = hci_req_run(&req, set_class_complete);
2614 if (err < 0) {
2615 if (err != -ENODATA)
2616 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002617
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002618 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2619 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002620 goto unlock;
2621 }
2622
2623 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002624 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002625 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002626 goto unlock;
2627 }
2628
2629 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002630
Johan Hedbergb5235a62012-02-21 14:32:24 +02002631unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002632 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002633 return err;
2634}
2635
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002636static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002637 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002638{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002639 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002640 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2641 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002642 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002643 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002644 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002645
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002646 BT_DBG("request for %s", hdev->name);
2647
2648 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002649 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2650 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002651
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002652 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002653 if (key_count > max_key_count) {
2654 BT_ERR("load_link_keys: too big key_count value %u",
2655 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002656 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2657 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002658 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002659
Johan Hedberg86742e12011-11-07 23:13:38 +02002660 expected_len = sizeof(*cp) + key_count *
2661 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002662 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002663 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002664 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002665 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2666 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002667 }
2668
Johan Hedberg4ae14302013-01-20 14:27:13 +02002669 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002670 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2671 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002672
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002673 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002674 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002675
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002676 for (i = 0; i < key_count; i++) {
2677 struct mgmt_link_key_info *key = &cp->keys[i];
2678
Marcel Holtmann8e991132014-01-10 02:07:25 -08002679 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002680 return mgmt_cmd_status(sk, hdev->id,
2681 MGMT_OP_LOAD_LINK_KEYS,
2682 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002683 }
2684
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002685 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002686
2687 hci_link_keys_clear(hdev);
2688
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002689 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002690 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002691 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002692 changed = hci_dev_test_and_clear_flag(hdev,
2693 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002694
2695 if (changed)
2696 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002697
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002698 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002699 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002700
Johan Hedberg58e92932014-06-24 14:00:26 +03002701 /* Always ignore debug keys and require a new pairing if
2702 * the user wants to use them.
2703 */
2704 if (key->type == HCI_LK_DEBUG_COMBINATION)
2705 continue;
2706
Johan Hedberg7652ff62014-06-24 13:15:49 +03002707 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2708 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002709 }
2710
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002711 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002712
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002713 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002714
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002715 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002716}
2717
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002718static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002719 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002720{
2721 struct mgmt_ev_device_unpaired ev;
2722
2723 bacpy(&ev.addr.bdaddr, bdaddr);
2724 ev.addr.type = addr_type;
2725
2726 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002727 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002728}
2729
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002730static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002731 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002732{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002733 struct mgmt_cp_unpair_device *cp = data;
2734 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002735 struct hci_cp_disconnect dc;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002736 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002737 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002738 int err;
2739
Johan Hedberga8a1d192011-11-10 15:54:38 +02002740 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002741 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2742 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002743
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002744 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002745 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2746 MGMT_STATUS_INVALID_PARAMS,
2747 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002748
Johan Hedberg118da702013-01-20 14:27:20 +02002749 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002750 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2751 MGMT_STATUS_INVALID_PARAMS,
2752 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002753
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002754 hci_dev_lock(hdev);
2755
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002756 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002757 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2758 MGMT_STATUS_NOT_POWERED, &rp,
2759 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002760 goto unlock;
2761 }
2762
Johan Hedberge0b2b272014-02-18 17:14:31 +02002763 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002764 /* If disconnection is requested, then look up the
2765 * connection. If the remote device is connected, it
2766 * will be later used to terminate the link.
2767 *
2768 * Setting it to NULL explicitly will cause no
2769 * termination of the link.
2770 */
2771 if (cp->disconnect)
2772 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2773 &cp->addr.bdaddr);
2774 else
2775 conn = NULL;
2776
Johan Hedberg124f6e32012-02-09 13:50:12 +02002777 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedberge0b2b272014-02-18 17:14:31 +02002778 } else {
2779 u8 addr_type;
2780
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002781 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
2782 &cp->addr.bdaddr);
2783 if (conn) {
2784 /* Defer clearing up the connection parameters
2785 * until closing to give a chance of keeping
2786 * them if a repairing happens.
2787 */
2788 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2789
2790 /* If disconnection is not requested, then
2791 * clear the connection variable so that the
2792 * link is not terminated.
2793 */
2794 if (!cp->disconnect)
2795 conn = NULL;
2796 }
2797
Johan Hedberge0b2b272014-02-18 17:14:31 +02002798 if (cp->addr.type == BDADDR_LE_PUBLIC)
2799 addr_type = ADDR_LE_DEV_PUBLIC;
2800 else
2801 addr_type = ADDR_LE_DEV_RANDOM;
2802
Johan Hedberga7ec7332014-02-18 17:14:35 +02002803 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2804
Johan Hedberge0b2b272014-02-18 17:14:31 +02002805 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
2806 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002807
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002808 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002809 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2810 MGMT_STATUS_NOT_PAIRED, &rp,
2811 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002812 goto unlock;
2813 }
2814
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002815 /* If the connection variable is set, then termination of the
2816 * link is requested.
2817 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002818 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002819 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2820 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002821 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002822 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002823 }
2824
Johan Hedberg124f6e32012-02-09 13:50:12 +02002825 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002826 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002827 if (!cmd) {
2828 err = -ENOMEM;
2829 goto unlock;
2830 }
2831
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002832 cmd->cmd_complete = addr_cmd_complete;
2833
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002834 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002835 dc.reason = 0x13; /* Remote User Terminated Connection */
2836 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2837 if (err < 0)
2838 mgmt_pending_remove(cmd);
2839
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002840unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002841 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002842 return err;
2843}
2844
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002845static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002846 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002847{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002848 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002849 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002850 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002851 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002852 int err;
2853
2854 BT_DBG("");
2855
Johan Hedberg06a63b12013-01-20 14:27:21 +02002856 memset(&rp, 0, sizeof(rp));
2857 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2858 rp.addr.type = cp->addr.type;
2859
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002860 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002861 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2862 MGMT_STATUS_INVALID_PARAMS,
2863 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002864
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002865 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002866
2867 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002868 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2869 MGMT_STATUS_NOT_POWERED, &rp,
2870 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002871 goto failed;
2872 }
2873
Johan Hedberg333ae952015-03-17 13:48:47 +02002874 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002875 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2876 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002877 goto failed;
2878 }
2879
Andre Guedes591f47f2012-04-24 21:02:49 -03002880 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002881 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2882 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002883 else
2884 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002885
Vishal Agarwalf9607272012-06-13 05:32:43 +05302886 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002887 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2888 MGMT_STATUS_NOT_CONNECTED, &rp,
2889 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002890 goto failed;
2891 }
2892
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002893 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002894 if (!cmd) {
2895 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002896 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002897 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002898
Johan Hedbergf5818c22014-12-05 13:36:02 +02002899 cmd->cmd_complete = generic_cmd_complete;
2900
Johan Hedberge3f2f922014-08-18 20:33:33 +03002901 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002902 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002903 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002904
2905failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002906 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002907 return err;
2908}
2909
Andre Guedes57c14772012-04-24 21:02:50 -03002910static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002911{
2912 switch (link_type) {
2913 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002914 switch (addr_type) {
2915 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002916 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002917
Johan Hedberg48264f02011-11-09 13:58:58 +02002918 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002919 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002920 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002921 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002922
Johan Hedberg4c659c32011-11-07 23:13:39 +02002923 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002924 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002925 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002926 }
2927}
2928
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002929static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2930 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002931{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002932 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002933 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002934 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002935 int err;
2936 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002937
2938 BT_DBG("");
2939
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002940 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002941
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002942 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002943 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2944 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002945 goto unlock;
2946 }
2947
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002948 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002949 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2950 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002951 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002952 }
2953
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002954 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002955 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002956 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002957 err = -ENOMEM;
2958 goto unlock;
2959 }
2960
Johan Hedberg2784eb42011-01-21 13:56:35 +02002961 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002962 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002963 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2964 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002965 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002966 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002967 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002968 continue;
2969 i++;
2970 }
2971
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002972 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002973
Johan Hedberg4c659c32011-11-07 23:13:39 +02002974 /* Recalculate length in case of filtered SCO connections, etc */
2975 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002976
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002977 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2978 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002979
Johan Hedberga38528f2011-01-22 06:46:43 +02002980 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002981
2982unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002983 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002984 return err;
2985}
2986
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002987static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002988 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002989{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002990 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002991 int err;
2992
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002993 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002994 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002995 if (!cmd)
2996 return -ENOMEM;
2997
Johan Hedbergd8457692012-02-17 14:24:57 +02002998 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002999 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003000 if (err < 0)
3001 mgmt_pending_remove(cmd);
3002
3003 return err;
3004}
3005
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003006static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003007 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003008{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003009 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003010 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003011 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003012 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003013 int err;
3014
3015 BT_DBG("");
3016
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003017 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003018
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003019 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003020 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3021 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003022 goto failed;
3023 }
3024
Johan Hedbergd8457692012-02-17 14:24:57 +02003025 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003026 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003027 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3028 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003029 goto failed;
3030 }
3031
3032 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02003033 struct mgmt_cp_pin_code_neg_reply ncp;
3034
3035 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003036
3037 BT_ERR("PIN code is not 16 bytes long");
3038
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003039 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003040 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02003041 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3042 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003043
3044 goto failed;
3045 }
3046
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03003047 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03003048 if (!cmd) {
3049 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003050 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03003051 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02003052
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003053 cmd->cmd_complete = addr_cmd_complete;
3054
Johan Hedbergd8457692012-02-17 14:24:57 +02003055 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003056 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02003057 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003058
3059 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
3060 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03003061 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003062
3063failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003064 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003065 return err;
3066}
3067
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003068static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
3069 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003070{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003071 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003072
3073 BT_DBG("");
3074
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003075 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003076 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
3077 MGMT_STATUS_INVALID_PARAMS, NULL, 0);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003078
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003079 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003080
3081 hdev->io_capability = cp->io_capability;
3082
3083 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003084 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003085
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003086 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003087
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003088 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
3089 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003090}
3091
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003092static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003093{
3094 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003095 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003096
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003097 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03003098 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
3099 continue;
3100
Johan Hedberge9a416b2011-02-19 12:05:56 -03003101 if (cmd->user_data != conn)
3102 continue;
3103
3104 return cmd;
3105 }
3106
3107 return NULL;
3108}
3109
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003110static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003111{
3112 struct mgmt_rp_pair_device rp;
3113 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02003114 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003115
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02003116 bacpy(&rp.addr.bdaddr, &conn->dst);
3117 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003118
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003119 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
3120 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003121
3122 /* So we don't get further callbacks for this connection */
3123 conn->connect_cfm_cb = NULL;
3124 conn->security_cfm_cb = NULL;
3125 conn->disconn_cfm_cb = NULL;
3126
David Herrmann76a68ba2013-04-06 20:28:37 +02003127 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00003128
3129 /* The device is paired so there is no need to remove
3130 * its connection parameters anymore.
3131 */
3132 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02003133
3134 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02003135
3136 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003137}
3138
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003139void mgmt_smp_complete(struct hci_conn *conn, bool complete)
3140{
3141 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003142 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003143
3144 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003145 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02003146 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02003147 mgmt_pending_remove(cmd);
3148 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003149}
3150
Johan Hedberge9a416b2011-02-19 12:05:56 -03003151static void pairing_complete_cb(struct hci_conn *conn, u8 status)
3152{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003153 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003154
3155 BT_DBG("status %u", status);
3156
Johan Hedberg56e5cb82011-11-08 20:40:16 +02003157 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003158 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02003159 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02003160 return;
3161 }
3162
3163 cmd->cmd_complete(cmd, mgmt_status(status));
3164 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003165}
3166
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003167static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303168{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003169 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303170
3171 BT_DBG("status %u", status);
3172
3173 if (!status)
3174 return;
3175
3176 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003177 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303178 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02003179 return;
3180 }
3181
3182 cmd->cmd_complete(cmd, mgmt_status(status));
3183 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303184}
3185
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003186static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003187 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003188{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003189 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02003190 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003191 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003192 u8 sec_level, auth_type;
3193 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003194 int err;
3195
3196 BT_DBG("");
3197
Szymon Jancf950a30e2013-01-18 12:48:07 +01003198 memset(&rp, 0, sizeof(rp));
3199 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3200 rp.addr.type = cp->addr.type;
3201
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003202 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003203 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3204 MGMT_STATUS_INVALID_PARAMS,
3205 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003206
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003207 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003208 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3209 MGMT_STATUS_INVALID_PARAMS,
3210 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003211
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003212 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003213
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003214 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003215 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3216 MGMT_STATUS_NOT_POWERED, &rp,
3217 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003218 goto unlock;
3219 }
3220
Johan Hedberg55e76b32015-03-10 22:34:40 +02003221 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
3222 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3223 MGMT_STATUS_ALREADY_PAIRED, &rp,
3224 sizeof(rp));
3225 goto unlock;
3226 }
3227
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03003228 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02003229 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003230
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003231 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03003232 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
3233 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003234 } else {
3235 u8 addr_type;
3236
3237 /* Convert from L2CAP channel address type to HCI address type
3238 */
3239 if (cp->addr.type == BDADDR_LE_PUBLIC)
3240 addr_type = ADDR_LE_DEV_PUBLIC;
3241 else
3242 addr_type = ADDR_LE_DEV_RANDOM;
3243
Marcel Holtmann7c264b12014-06-30 12:34:40 +02003244 /* When pairing a new device, it is expected to remember
3245 * this device for future connections. Adding the connection
3246 * parameter information ahead of time allows tracking
3247 * of the slave preferred values and will speed up any
3248 * further connection establishment.
3249 *
3250 * If connection parameters already exist, then they
3251 * will be kept and this function does nothing.
3252 */
3253 hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
3254
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003255 conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type,
Johan Hedberge804d252014-07-16 11:42:28 +03003256 sec_level, HCI_LE_CONN_TIMEOUT,
3257 HCI_ROLE_MASTER);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003258 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003259
Ville Tervo30e76272011-02-22 16:10:53 -03003260 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003261 int status;
3262
3263 if (PTR_ERR(conn) == -EBUSY)
3264 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01003265 else if (PTR_ERR(conn) == -EOPNOTSUPP)
3266 status = MGMT_STATUS_NOT_SUPPORTED;
3267 else if (PTR_ERR(conn) == -ECONNREFUSED)
3268 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003269 else
3270 status = MGMT_STATUS_CONNECT_FAILED;
3271
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003272 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3273 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003274 goto unlock;
3275 }
3276
3277 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02003278 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003279 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3280 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003281 goto unlock;
3282 }
3283
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003284 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003285 if (!cmd) {
3286 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02003287 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003288 goto unlock;
3289 }
3290
Johan Hedberg04ab2742014-12-05 13:36:04 +02003291 cmd->cmd_complete = pairing_complete;
3292
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003293 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003294 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003295 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003296 conn->security_cfm_cb = pairing_complete_cb;
3297 conn->disconn_cfm_cb = pairing_complete_cb;
3298 } else {
3299 conn->connect_cfm_cb = le_pairing_complete_cb;
3300 conn->security_cfm_cb = le_pairing_complete_cb;
3301 conn->disconn_cfm_cb = le_pairing_complete_cb;
3302 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003303
Johan Hedberge9a416b2011-02-19 12:05:56 -03003304 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003305 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003306
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003307 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003308 hci_conn_security(conn, sec_level, auth_type, true)) {
3309 cmd->cmd_complete(cmd, 0);
3310 mgmt_pending_remove(cmd);
3311 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003312
3313 err = 0;
3314
3315unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003316 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003317 return err;
3318}
3319
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003320static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3321 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003322{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003323 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003324 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003325 struct hci_conn *conn;
3326 int err;
3327
3328 BT_DBG("");
3329
Johan Hedberg28424702012-02-02 04:02:29 +02003330 hci_dev_lock(hdev);
3331
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003332 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003333 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3334 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003335 goto unlock;
3336 }
3337
Johan Hedberg333ae952015-03-17 13:48:47 +02003338 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003339 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003340 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3341 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003342 goto unlock;
3343 }
3344
3345 conn = cmd->user_data;
3346
3347 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003348 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3349 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003350 goto unlock;
3351 }
3352
Johan Hedberga511b352014-12-11 21:45:45 +02003353 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3354 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003355
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003356 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3357 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003358unlock:
3359 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003360 return err;
3361}
3362
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003363static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003364 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003365 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003366{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003367 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003368 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003369 int err;
3370
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003371 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003372
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003373 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003374 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3375 MGMT_STATUS_NOT_POWERED, addr,
3376 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003377 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003378 }
3379
Johan Hedberg1707c602013-03-15 17:07:15 -05003380 if (addr->type == BDADDR_BREDR)
3381 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003382 else
Johan Hedberg1707c602013-03-15 17:07:15 -05003383 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08003384
Johan Hedberg272d90d2012-02-09 15:26:12 +02003385 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003386 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3387 MGMT_STATUS_NOT_CONNECTED, addr,
3388 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003389 goto done;
3390 }
3391
Johan Hedberg1707c602013-03-15 17:07:15 -05003392 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003393 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003394 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003395 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3396 MGMT_STATUS_SUCCESS, addr,
3397 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003398 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003399 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3400 MGMT_STATUS_FAILED, addr,
3401 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003402
Brian Gix47c15e22011-11-16 13:53:14 -08003403 goto done;
3404 }
3405
Johan Hedberg1707c602013-03-15 17:07:15 -05003406 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003407 if (!cmd) {
3408 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003409 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003410 }
3411
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003412 cmd->cmd_complete = addr_cmd_complete;
3413
Brian Gix0df4c182011-11-16 13:53:13 -08003414 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003415 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3416 struct hci_cp_user_passkey_reply cp;
3417
Johan Hedberg1707c602013-03-15 17:07:15 -05003418 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003419 cp.passkey = passkey;
3420 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3421 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003422 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3423 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003424
Johan Hedberga664b5b2011-02-19 12:06:02 -03003425 if (err < 0)
3426 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003427
Brian Gix0df4c182011-11-16 13:53:13 -08003428done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003429 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003430 return err;
3431}
3432
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303433static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3434 void *data, u16 len)
3435{
3436 struct mgmt_cp_pin_code_neg_reply *cp = data;
3437
3438 BT_DBG("");
3439
Johan Hedberg1707c602013-03-15 17:07:15 -05003440 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303441 MGMT_OP_PIN_CODE_NEG_REPLY,
3442 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3443}
3444
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003445static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3446 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003447{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003448 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003449
3450 BT_DBG("");
3451
3452 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003453 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3454 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003455
Johan Hedberg1707c602013-03-15 17:07:15 -05003456 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003457 MGMT_OP_USER_CONFIRM_REPLY,
3458 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003459}
3460
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003461static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003462 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003463{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003464 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003465
3466 BT_DBG("");
3467
Johan Hedberg1707c602013-03-15 17:07:15 -05003468 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003469 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3470 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003471}
3472
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003473static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3474 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003475{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003476 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003477
3478 BT_DBG("");
3479
Johan Hedberg1707c602013-03-15 17:07:15 -05003480 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003481 MGMT_OP_USER_PASSKEY_REPLY,
3482 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003483}
3484
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003485static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003486 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003487{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003488 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003489
3490 BT_DBG("");
3491
Johan Hedberg1707c602013-03-15 17:07:15 -05003492 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003493 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3494 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003495}
3496
Johan Hedberg13928972013-03-15 17:07:00 -05003497static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003498{
Johan Hedberg13928972013-03-15 17:07:00 -05003499 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003500 struct hci_cp_write_local_name cp;
3501
Johan Hedberg13928972013-03-15 17:07:00 -05003502 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003503
Johan Hedberg890ea892013-03-15 17:06:52 -05003504 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003505}
3506
Marcel Holtmann1904a852015-01-11 13:50:44 -08003507static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003508{
3509 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003510 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003511
3512 BT_DBG("status 0x%02x", status);
3513
3514 hci_dev_lock(hdev);
3515
Johan Hedberg333ae952015-03-17 13:48:47 +02003516 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003517 if (!cmd)
3518 goto unlock;
3519
3520 cp = cmd->param;
3521
3522 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003523 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3524 mgmt_status(status));
Johan Hedberg13928972013-03-15 17:07:00 -05003525 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003526 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3527 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003528
3529 mgmt_pending_remove(cmd);
3530
3531unlock:
3532 hci_dev_unlock(hdev);
3533}
3534
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003535static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003536 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003537{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003538 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003539 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003540 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003541 int err;
3542
3543 BT_DBG("");
3544
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003545 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003546
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003547 /* If the old values are the same as the new ones just return a
3548 * direct command complete event.
3549 */
3550 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3551 !memcmp(hdev->short_name, cp->short_name,
3552 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003553 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3554 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003555 goto failed;
3556 }
3557
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003558 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003559
Johan Hedbergb5235a62012-02-21 14:32:24 +02003560 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003561 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003562
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003563 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3564 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003565 if (err < 0)
3566 goto failed;
3567
Marcel Holtmannf6b77122015-03-14 19:28:05 -07003568 err = mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev,
3569 data, len, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003570
Johan Hedbergb5235a62012-02-21 14:32:24 +02003571 goto failed;
3572 }
3573
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003574 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003575 if (!cmd) {
3576 err = -ENOMEM;
3577 goto failed;
3578 }
3579
Johan Hedberg13928972013-03-15 17:07:00 -05003580 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3581
Johan Hedberg890ea892013-03-15 17:06:52 -05003582 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003583
3584 if (lmp_bredr_capable(hdev)) {
3585 update_name(&req);
3586 update_eir(&req);
3587 }
3588
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003589 /* The name is stored in the scan response data and so
3590 * no need to udpate the advertising data here.
3591 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003592 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003593 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003594
Johan Hedberg13928972013-03-15 17:07:00 -05003595 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003596 if (err < 0)
3597 mgmt_pending_remove(cmd);
3598
3599failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003600 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003601 return err;
3602}
3603
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003604static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003605 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003606{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003607 struct mgmt_pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01003608 int err;
3609
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003610 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003611
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003612 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003613
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003614 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003615 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3616 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003617 goto unlock;
3618 }
3619
Andre Guedes9a1a1992012-07-24 15:03:48 -03003620 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003621 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3622 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003623 goto unlock;
3624 }
3625
Johan Hedberg333ae952015-03-17 13:48:47 +02003626 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003627 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3628 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003629 goto unlock;
3630 }
3631
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003632 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003633 if (!cmd) {
3634 err = -ENOMEM;
3635 goto unlock;
3636 }
3637
Johan Hedberg710f11c2014-05-26 11:21:22 +03003638 if (bredr_sc_enabled(hdev))
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003639 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
3640 0, NULL);
3641 else
3642 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3643
Szymon Jancc35938b2011-03-22 13:12:21 +01003644 if (err < 0)
3645 mgmt_pending_remove(cmd);
3646
3647unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003648 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003649 return err;
3650}
3651
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003652static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003653 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003654{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003655 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003656 int err;
3657
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003658 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003659
Johan Hedberg5d57e792015-01-23 10:10:38 +02003660 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003661 return mgmt_cmd_complete(sk, hdev->id,
3662 MGMT_OP_ADD_REMOTE_OOB_DATA,
3663 MGMT_STATUS_INVALID_PARAMS,
3664 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003665
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003666 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003667
Marcel Holtmannec109112014-01-10 02:07:30 -08003668 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3669 struct mgmt_cp_add_remote_oob_data *cp = data;
3670 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003671
Johan Hedbergc19a4952014-11-17 20:52:19 +02003672 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003673 err = mgmt_cmd_complete(sk, hdev->id,
3674 MGMT_OP_ADD_REMOTE_OOB_DATA,
3675 MGMT_STATUS_INVALID_PARAMS,
3676 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003677 goto unlock;
3678 }
3679
Marcel Holtmannec109112014-01-10 02:07:30 -08003680 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003681 cp->addr.type, cp->hash,
3682 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003683 if (err < 0)
3684 status = MGMT_STATUS_FAILED;
3685 else
3686 status = MGMT_STATUS_SUCCESS;
3687
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003688 err = mgmt_cmd_complete(sk, hdev->id,
3689 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3690 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003691 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3692 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003693 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003694 u8 status;
3695
Johan Hedberg86df9202014-10-26 20:52:27 +01003696 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003697 /* Enforce zero-valued 192-bit parameters as
3698 * long as legacy SMP OOB isn't implemented.
3699 */
3700 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3701 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003702 err = mgmt_cmd_complete(sk, hdev->id,
3703 MGMT_OP_ADD_REMOTE_OOB_DATA,
3704 MGMT_STATUS_INVALID_PARAMS,
3705 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003706 goto unlock;
3707 }
3708
Johan Hedberg86df9202014-10-26 20:52:27 +01003709 rand192 = NULL;
3710 hash192 = NULL;
3711 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003712 /* In case one of the P-192 values is set to zero,
3713 * then just disable OOB data for P-192.
3714 */
3715 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3716 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3717 rand192 = NULL;
3718 hash192 = NULL;
3719 } else {
3720 rand192 = cp->rand192;
3721 hash192 = cp->hash192;
3722 }
3723 }
3724
3725 /* In case one of the P-256 values is set to zero, then just
3726 * disable OOB data for P-256.
3727 */
3728 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3729 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3730 rand256 = NULL;
3731 hash256 = NULL;
3732 } else {
3733 rand256 = cp->rand256;
3734 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003735 }
3736
Johan Hedberg81328d52014-10-26 20:33:47 +01003737 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003738 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003739 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003740 if (err < 0)
3741 status = MGMT_STATUS_FAILED;
3742 else
3743 status = MGMT_STATUS_SUCCESS;
3744
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003745 err = mgmt_cmd_complete(sk, hdev->id,
3746 MGMT_OP_ADD_REMOTE_OOB_DATA,
3747 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003748 } else {
3749 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003750 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3751 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003752 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003753
Johan Hedbergc19a4952014-11-17 20:52:19 +02003754unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003755 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003756 return err;
3757}
3758
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003759static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003760 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003761{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003762 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003763 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003764 int err;
3765
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003766 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003767
Johan Hedbergc19a4952014-11-17 20:52:19 +02003768 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003769 return mgmt_cmd_complete(sk, hdev->id,
3770 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3771 MGMT_STATUS_INVALID_PARAMS,
3772 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003773
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003774 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003775
Johan Hedbergeedbd582014-11-15 09:34:23 +02003776 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3777 hci_remote_oob_data_clear(hdev);
3778 status = MGMT_STATUS_SUCCESS;
3779 goto done;
3780 }
3781
Johan Hedberg6928a922014-10-26 20:46:09 +01003782 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003783 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003784 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003785 else
Szymon Janca6785be2012-12-13 15:11:21 +01003786 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003787
Johan Hedbergeedbd582014-11-15 09:34:23 +02003788done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003789 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3790 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003791
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003792 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003793 return err;
3794}
3795
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003796static bool trigger_bredr_inquiry(struct hci_request *req, u8 *status)
3797{
3798 struct hci_dev *hdev = req->hdev;
3799 struct hci_cp_inquiry cp;
3800 /* General inquiry access code (GIAC) */
3801 u8 lap[3] = { 0x33, 0x8b, 0x9e };
3802
3803 *status = mgmt_bredr_support(hdev);
3804 if (*status)
3805 return false;
3806
3807 if (hci_dev_test_flag(hdev, HCI_INQUIRY)) {
3808 *status = MGMT_STATUS_BUSY;
3809 return false;
3810 }
3811
3812 hci_inquiry_cache_flush(hdev);
3813
3814 memset(&cp, 0, sizeof(cp));
3815 memcpy(&cp.lap, lap, sizeof(cp.lap));
3816 cp.length = DISCOV_BREDR_INQUIRY_LEN;
3817
3818 hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp);
3819
3820 return true;
3821}
3822
3823static bool trigger_le_scan(struct hci_request *req, u16 interval, u8 *status)
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003824{
Marcel Holtmann80190442014-12-04 11:36:36 +01003825 struct hci_dev *hdev = req->hdev;
3826 struct hci_cp_le_set_scan_param param_cp;
3827 struct hci_cp_le_set_scan_enable enable_cp;
Marcel Holtmann80190442014-12-04 11:36:36 +01003828 u8 own_addr_type;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003829 int err;
3830
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003831 *status = mgmt_le_support(hdev);
3832 if (*status)
3833 return false;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003834
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003835 if (hci_dev_test_flag(hdev, HCI_LE_ADV)) {
3836 /* Don't let discovery abort an outgoing connection attempt
3837 * that's using directed advertising.
3838 */
3839 if (hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT)) {
3840 *status = MGMT_STATUS_REJECTED;
Marcel Holtmann80190442014-12-04 11:36:36 +01003841 return false;
3842 }
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003843
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003844 disable_advertising(req);
3845 }
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003846
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003847 /* If controller is scanning, it means the background scanning is
3848 * running. Thus, we should temporarily stop it in order to set the
3849 * discovery scanning parameters.
3850 */
3851 if (hci_dev_test_flag(hdev, HCI_LE_SCAN))
3852 hci_req_add_le_scan_disable(req);
3853
3854 /* All active scans will be done with either a resolvable private
3855 * address (when privacy feature has been enabled) or non-resolvable
3856 * private address.
3857 */
3858 err = hci_update_random_address(req, true, &own_addr_type);
3859 if (err < 0) {
3860 *status = MGMT_STATUS_FAILED;
3861 return false;
3862 }
3863
3864 memset(&param_cp, 0, sizeof(param_cp));
3865 param_cp.type = LE_SCAN_ACTIVE;
3866 param_cp.interval = cpu_to_le16(interval);
3867 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
3868 param_cp.own_address_type = own_addr_type;
3869
3870 hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3871 &param_cp);
3872
3873 memset(&enable_cp, 0, sizeof(enable_cp));
3874 enable_cp.enable = LE_SCAN_ENABLE;
3875 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3876
3877 hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3878 &enable_cp);
3879
3880 return true;
3881}
3882
3883static bool trigger_discovery(struct hci_request *req, u8 *status)
3884{
3885 struct hci_dev *hdev = req->hdev;
3886
3887 switch (hdev->discovery.type) {
3888 case DISCOV_TYPE_BREDR:
3889 if (!trigger_bredr_inquiry(req, status))
3890 return false;
Marcel Holtmann80190442014-12-04 11:36:36 +01003891 break;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003892
Marcel Holtmann80190442014-12-04 11:36:36 +01003893 case DISCOV_TYPE_INTERLEAVED:
Jakub Pawlowski07d23342015-03-17 09:04:14 -07003894 if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY,
3895 &hdev->quirks)) {
3896 /* During simultaneous discovery, we double LE scan
3897 * interval. We must leave some time for the controller
3898 * to do BR/EDR inquiry.
3899 */
3900 if (!trigger_le_scan(req, DISCOV_LE_SCAN_INT * 2,
3901 status))
3902 return false;
3903
3904 if (!trigger_bredr_inquiry(req, status))
3905 return false;
3906
3907 return true;
3908 }
3909
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003910 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmann80190442014-12-04 11:36:36 +01003911 *status = MGMT_STATUS_NOT_SUPPORTED;
3912 return false;
3913 }
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003914 /* fall through */
Marcel Holtmann80190442014-12-04 11:36:36 +01003915
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003916 case DISCOV_TYPE_LE:
3917 if (!trigger_le_scan(req, DISCOV_LE_SCAN_INT, status))
Marcel Holtmann80190442014-12-04 11:36:36 +01003918 return false;
Marcel Holtmann80190442014-12-04 11:36:36 +01003919 break;
3920
3921 default:
3922 *status = MGMT_STATUS_INVALID_PARAMS;
3923 return false;
3924 }
3925
3926 return true;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003927}
3928
Marcel Holtmann1904a852015-01-11 13:50:44 -08003929static void start_discovery_complete(struct hci_dev *hdev, u8 status,
3930 u16 opcode)
Andre Guedes7c307722013-04-30 15:29:28 -03003931{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003932 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003933 unsigned long timeout;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003934
Andre Guedes7c307722013-04-30 15:29:28 -03003935 BT_DBG("status %d", status);
3936
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003937 hci_dev_lock(hdev);
3938
Johan Hedberg333ae952015-03-17 13:48:47 +02003939 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003940 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003941 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003942
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003943 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003944 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003945 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003946 }
3947
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003948 if (status) {
3949 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3950 goto unlock;
3951 }
3952
Andre Guedes7c307722013-04-30 15:29:28 -03003953 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
Andre Guedes7c307722013-04-30 15:29:28 -03003954
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08003955 /* If the scan involves LE scan, pick proper timeout to schedule
3956 * hdev->le_scan_disable that will stop it.
3957 */
Andre Guedes7c307722013-04-30 15:29:28 -03003958 switch (hdev->discovery.type) {
3959 case DISCOV_TYPE_LE:
Lukasz Rymanowski3d5a76f2014-03-27 20:55:21 +01003960 timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003961 break;
Andre Guedes7c307722013-04-30 15:29:28 -03003962 case DISCOV_TYPE_INTERLEAVED:
Jakub Pawlowski07d23342015-03-17 09:04:14 -07003963 /* When running simultaneous discovery, the LE scanning time
3964 * should occupy the whole discovery time sine BR/EDR inquiry
3965 * and LE scanning are scheduled by the controller.
3966 *
3967 * For interleaving discovery in comparison, BR/EDR inquiry
3968 * and LE scanning are done sequentially with separate
3969 * timeouts.
3970 */
3971 if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks))
3972 timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
3973 else
3974 timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
Andre Guedes7c307722013-04-30 15:29:28 -03003975 break;
Andre Guedes7c307722013-04-30 15:29:28 -03003976 case DISCOV_TYPE_BREDR:
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003977 timeout = 0;
Andre Guedes7c307722013-04-30 15:29:28 -03003978 break;
Andre Guedes7c307722013-04-30 15:29:28 -03003979 default:
3980 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003981 timeout = 0;
3982 break;
Andre Guedes7c307722013-04-30 15:29:28 -03003983 }
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003984
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08003985 if (timeout) {
3986 /* When service discovery is used and the controller has
3987 * a strict duplicate filter, it is important to remember
3988 * the start and duration of the scan. This is required
3989 * for restarting scanning during the discovery phase.
3990 */
3991 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER,
3992 &hdev->quirks) &&
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08003993 hdev->discovery.result_filtering) {
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08003994 hdev->discovery.scan_start = jiffies;
3995 hdev->discovery.scan_duration = timeout;
3996 }
3997
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003998 queue_delayed_work(hdev->workqueue,
3999 &hdev->le_scan_disable, timeout);
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004000 }
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004001
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004002unlock:
4003 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03004004}
4005
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004006static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004007 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004008{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004009 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004010 struct mgmt_pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03004011 struct hci_request req;
Marcel Holtmann80190442014-12-04 11:36:36 +01004012 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04004013 int err;
4014
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004015 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004016
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004017 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004018
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004019 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004020 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4021 MGMT_STATUS_NOT_POWERED,
4022 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02004023 goto failed;
4024 }
4025
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004026 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004027 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004028 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4029 MGMT_STATUS_BUSY, &cp->type,
4030 sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03004031 goto failed;
4032 }
4033
Johan Hedberg2922a942014-12-05 13:36:06 +02004034 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004035 if (!cmd) {
4036 err = -ENOMEM;
4037 goto failed;
4038 }
4039
Johan Hedberg2922a942014-12-05 13:36:06 +02004040 cmd->cmd_complete = generic_cmd_complete;
4041
Marcel Holtmann22078802014-12-05 11:45:22 +01004042 /* Clear the discovery filter first to free any previously
4043 * allocated memory for the UUID list.
4044 */
4045 hci_discovery_filter_clear(hdev);
4046
Andre Guedes4aab14e2012-02-17 20:39:36 -03004047 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01004048 hdev->discovery.report_invalid_rssi = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03004049
Andre Guedes7c307722013-04-30 15:29:28 -03004050 hci_req_init(&req, hdev);
4051
Marcel Holtmann80190442014-12-04 11:36:36 +01004052 if (!trigger_discovery(&req, &status)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004053 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4054 status, &cp->type, sizeof(cp->type));
Johan Hedberg04106752013-01-10 14:54:09 +02004055 mgmt_pending_remove(cmd);
4056 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004057 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004058
Andre Guedes7c307722013-04-30 15:29:28 -03004059 err = hci_req_run(&req, start_discovery_complete);
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004060 if (err < 0) {
Johan Hedberg14a53662011-04-27 10:29:56 -04004061 mgmt_pending_remove(cmd);
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004062 goto failed;
4063 }
4064
4065 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04004066
4067failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004068 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004069 return err;
4070}
4071
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004072static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4073 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004074{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004075 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4076 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004077}
4078
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004079static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4080 void *data, u16 len)
4081{
4082 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004083 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004084 struct hci_request req;
4085 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4086 u16 uuid_count, expected_len;
4087 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004088 int err;
4089
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004090 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004091
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004092 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004093
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004094 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004095 err = mgmt_cmd_complete(sk, hdev->id,
4096 MGMT_OP_START_SERVICE_DISCOVERY,
4097 MGMT_STATUS_NOT_POWERED,
4098 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004099 goto failed;
4100 }
4101
4102 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004103 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004104 err = mgmt_cmd_complete(sk, hdev->id,
4105 MGMT_OP_START_SERVICE_DISCOVERY,
4106 MGMT_STATUS_BUSY, &cp->type,
4107 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004108 goto failed;
4109 }
4110
4111 uuid_count = __le16_to_cpu(cp->uuid_count);
4112 if (uuid_count > max_uuid_count) {
4113 BT_ERR("service_discovery: too big uuid_count value %u",
4114 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004115 err = mgmt_cmd_complete(sk, hdev->id,
4116 MGMT_OP_START_SERVICE_DISCOVERY,
4117 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4118 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004119 goto failed;
4120 }
4121
4122 expected_len = sizeof(*cp) + uuid_count * 16;
4123 if (expected_len != len) {
4124 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
4125 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004126 err = mgmt_cmd_complete(sk, hdev->id,
4127 MGMT_OP_START_SERVICE_DISCOVERY,
4128 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4129 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004130 goto failed;
4131 }
4132
4133 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02004134 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004135 if (!cmd) {
4136 err = -ENOMEM;
4137 goto failed;
4138 }
4139
Johan Hedberg2922a942014-12-05 13:36:06 +02004140 cmd->cmd_complete = service_discovery_cmd_complete;
4141
Marcel Holtmann22078802014-12-05 11:45:22 +01004142 /* Clear the discovery filter first to free any previously
4143 * allocated memory for the UUID list.
4144 */
4145 hci_discovery_filter_clear(hdev);
4146
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004147 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004148 hdev->discovery.type = cp->type;
4149 hdev->discovery.rssi = cp->rssi;
4150 hdev->discovery.uuid_count = uuid_count;
4151
4152 if (uuid_count > 0) {
4153 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4154 GFP_KERNEL);
4155 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004156 err = mgmt_cmd_complete(sk, hdev->id,
4157 MGMT_OP_START_SERVICE_DISCOVERY,
4158 MGMT_STATUS_FAILED,
4159 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004160 mgmt_pending_remove(cmd);
4161 goto failed;
4162 }
4163 }
4164
4165 hci_req_init(&req, hdev);
4166
4167 if (!trigger_discovery(&req, &status)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004168 err = mgmt_cmd_complete(sk, hdev->id,
4169 MGMT_OP_START_SERVICE_DISCOVERY,
4170 status, &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004171 mgmt_pending_remove(cmd);
4172 goto failed;
4173 }
4174
4175 err = hci_req_run(&req, start_discovery_complete);
4176 if (err < 0) {
4177 mgmt_pending_remove(cmd);
4178 goto failed;
4179 }
4180
4181 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
4182
4183failed:
4184 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004185 return err;
4186}
4187
Marcel Holtmann1904a852015-01-11 13:50:44 -08004188static void stop_discovery_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004189{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004190 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004191
Andre Guedes0e05bba2013-04-30 15:29:33 -03004192 BT_DBG("status %d", status);
4193
4194 hci_dev_lock(hdev);
4195
Johan Hedberg333ae952015-03-17 13:48:47 +02004196 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004197 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004198 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004199 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004200 }
4201
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004202 if (!status)
4203 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004204
Andre Guedes0e05bba2013-04-30 15:29:33 -03004205 hci_dev_unlock(hdev);
4206}
4207
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004208static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004209 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004210{
Johan Hedbergd9306502012-02-20 23:25:18 +02004211 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004212 struct mgmt_pending_cmd *cmd;
Andre Guedes0e05bba2013-04-30 15:29:33 -03004213 struct hci_request req;
Johan Hedberg14a53662011-04-27 10:29:56 -04004214 int err;
4215
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004216 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004217
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004218 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004219
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004220 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004221 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4222 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4223 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004224 goto unlock;
4225 }
4226
4227 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004228 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4229 MGMT_STATUS_INVALID_PARAMS,
4230 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004231 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004232 }
4233
Johan Hedberg2922a942014-12-05 13:36:06 +02004234 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004235 if (!cmd) {
4236 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004237 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004238 }
4239
Johan Hedberg2922a942014-12-05 13:36:06 +02004240 cmd->cmd_complete = generic_cmd_complete;
4241
Andre Guedes0e05bba2013-04-30 15:29:33 -03004242 hci_req_init(&req, hdev);
4243
Johan Hedberg21a60d32014-06-10 14:05:58 +03004244 hci_stop_discovery(&req);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004245
Johan Hedberg21a60d32014-06-10 14:05:58 +03004246 err = hci_req_run(&req, stop_discovery_complete);
4247 if (!err) {
4248 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004249 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004250 }
4251
Johan Hedberg21a60d32014-06-10 14:05:58 +03004252 mgmt_pending_remove(cmd);
4253
4254 /* If no HCI commands were sent we're done */
4255 if (err == -ENODATA) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004256 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
4257 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg21a60d32014-06-10 14:05:58 +03004258 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
4259 }
Johan Hedberg14a53662011-04-27 10:29:56 -04004260
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004261unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004262 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004263 return err;
4264}
4265
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004266static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004267 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004268{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004269 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004270 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004271 int err;
4272
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004273 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004274
Johan Hedberg561aafb2012-01-04 13:31:59 +02004275 hci_dev_lock(hdev);
4276
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004277 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004278 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4279 MGMT_STATUS_FAILED, &cp->addr,
4280 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004281 goto failed;
4282 }
4283
Johan Hedberga198e7b2012-02-17 14:27:06 +02004284 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004285 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004286 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4287 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4288 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004289 goto failed;
4290 }
4291
4292 if (cp->name_known) {
4293 e->name_state = NAME_KNOWN;
4294 list_del(&e->list);
4295 } else {
4296 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02004297 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004298 }
4299
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004300 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4301 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004302
4303failed:
4304 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004305 return err;
4306}
4307
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004308static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004309 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004310{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004311 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004312 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004313 int err;
4314
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004315 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004316
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004317 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004318 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4319 MGMT_STATUS_INVALID_PARAMS,
4320 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004321
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004322 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004323
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004324 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4325 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004326 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004327 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004328 goto done;
4329 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004330
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004331 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4332 sk);
4333 status = MGMT_STATUS_SUCCESS;
4334
4335done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004336 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4337 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004338
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004339 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004340
4341 return err;
4342}
4343
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004344static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004345 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004346{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004347 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004348 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004349 int err;
4350
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004351 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004352
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004353 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004354 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4355 MGMT_STATUS_INVALID_PARAMS,
4356 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004357
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004358 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004359
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004360 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4361 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004362 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004363 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004364 goto done;
4365 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004366
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004367 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4368 sk);
4369 status = MGMT_STATUS_SUCCESS;
4370
4371done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004372 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4373 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004374
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004375 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004376
4377 return err;
4378}
4379
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004380static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4381 u16 len)
4382{
4383 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004384 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004385 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004386 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004387
4388 BT_DBG("%s", hdev->name);
4389
Szymon Jancc72d4b82012-03-16 16:02:57 +01004390 source = __le16_to_cpu(cp->source);
4391
4392 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004393 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4394 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004395
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004396 hci_dev_lock(hdev);
4397
Szymon Jancc72d4b82012-03-16 16:02:57 +01004398 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004399 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4400 hdev->devid_product = __le16_to_cpu(cp->product);
4401 hdev->devid_version = __le16_to_cpu(cp->version);
4402
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004403 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4404 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004405
Johan Hedberg890ea892013-03-15 17:06:52 -05004406 hci_req_init(&req, hdev);
4407 update_eir(&req);
4408 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004409
4410 hci_dev_unlock(hdev);
4411
4412 return err;
4413}
4414
Arman Uguray24b4f382015-03-23 15:57:12 -07004415static void enable_advertising_instance(struct hci_dev *hdev, u8 status,
4416 u16 opcode)
4417{
4418 BT_DBG("status %d", status);
4419}
4420
Marcel Holtmann1904a852015-01-11 13:50:44 -08004421static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4422 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004423{
4424 struct cmd_lookup match = { NULL, hdev };
Arman Uguray24b4f382015-03-23 15:57:12 -07004425 struct hci_request req;
Johan Hedberg4375f102013-09-25 13:26:10 +03004426
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304427 hci_dev_lock(hdev);
4428
Johan Hedberg4375f102013-09-25 13:26:10 +03004429 if (status) {
4430 u8 mgmt_err = mgmt_status(status);
4431
4432 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4433 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304434 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004435 }
4436
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004437 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004438 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004439 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004440 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004441
Johan Hedberg4375f102013-09-25 13:26:10 +03004442 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4443 &match);
4444
4445 new_settings(hdev, match.sk);
4446
4447 if (match.sk)
4448 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304449
Arman Uguray24b4f382015-03-23 15:57:12 -07004450 /* If "Set Advertising" was just disabled and instance advertising was
4451 * set up earlier, then enable the advertising instance.
4452 */
4453 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
4454 !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
4455 goto unlock;
4456
4457 hci_req_init(&req, hdev);
4458
4459 update_adv_data(&req);
4460 enable_advertising(&req);
4461
4462 if (hci_req_run(&req, enable_advertising_instance) < 0)
4463 BT_ERR("Failed to re-configure advertising");
4464
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304465unlock:
4466 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004467}
4468
Marcel Holtmann21b51872013-10-10 09:47:53 -07004469static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4470 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004471{
4472 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004473 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004474 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004475 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004476 int err;
4477
4478 BT_DBG("request for %s", hdev->name);
4479
Johan Hedberge6fe7982013-10-02 15:45:22 +03004480 status = mgmt_le_support(hdev);
4481 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004482 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4483 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004484
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004485 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004486 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4487 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004488
4489 hci_dev_lock(hdev);
4490
4491 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004492
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004493 /* The following conditions are ones which mean that we should
4494 * not do any HCI communication but directly send a mgmt
4495 * response to user space (after toggling the flag if
4496 * necessary).
4497 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004498 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004499 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4500 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004501 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004502 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004503 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004504 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004505
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004506 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004507 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004508 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004509 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004510 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004511 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004512 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004513 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004514 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004515 }
4516
4517 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4518 if (err < 0)
4519 goto unlock;
4520
4521 if (changed)
4522 err = new_settings(hdev, sk);
4523
4524 goto unlock;
4525 }
4526
Johan Hedberg333ae952015-03-17 13:48:47 +02004527 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4528 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004529 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4530 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004531 goto unlock;
4532 }
4533
4534 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4535 if (!cmd) {
4536 err = -ENOMEM;
4537 goto unlock;
4538 }
4539
4540 hci_req_init(&req, hdev);
4541
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004542 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004543 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004544 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004545 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004546
Arman Uguray24b4f382015-03-23 15:57:12 -07004547 if (val) {
4548 /* Switch to instance "0" for the Set Advertising setting. */
4549 update_adv_data_for_instance(&req, 0);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004550 enable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004551 } else {
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004552 disable_advertising(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07004553 }
Johan Hedberg4375f102013-09-25 13:26:10 +03004554
4555 err = hci_req_run(&req, set_advertising_complete);
4556 if (err < 0)
4557 mgmt_pending_remove(cmd);
4558
4559unlock:
4560 hci_dev_unlock(hdev);
4561 return err;
4562}
4563
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004564static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4565 void *data, u16 len)
4566{
4567 struct mgmt_cp_set_static_address *cp = data;
4568 int err;
4569
4570 BT_DBG("%s", hdev->name);
4571
Marcel Holtmann62af4442013-10-02 22:10:32 -07004572 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004573 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4574 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004575
4576 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004577 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4578 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004579
4580 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4581 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004582 return mgmt_cmd_status(sk, hdev->id,
4583 MGMT_OP_SET_STATIC_ADDRESS,
4584 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004585
4586 /* Two most significant bits shall be set */
4587 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004588 return mgmt_cmd_status(sk, hdev->id,
4589 MGMT_OP_SET_STATIC_ADDRESS,
4590 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004591 }
4592
4593 hci_dev_lock(hdev);
4594
4595 bacpy(&hdev->static_addr, &cp->bdaddr);
4596
Marcel Holtmann93690c22015-03-06 10:11:21 -08004597 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4598 if (err < 0)
4599 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004600
Marcel Holtmann93690c22015-03-06 10:11:21 -08004601 err = new_settings(hdev, sk);
4602
4603unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004604 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004605 return err;
4606}
4607
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004608static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4609 void *data, u16 len)
4610{
4611 struct mgmt_cp_set_scan_params *cp = data;
4612 __u16 interval, window;
4613 int err;
4614
4615 BT_DBG("%s", hdev->name);
4616
4617 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004618 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4619 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004620
4621 interval = __le16_to_cpu(cp->interval);
4622
4623 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004624 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4625 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004626
4627 window = __le16_to_cpu(cp->window);
4628
4629 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004630 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4631 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004632
Marcel Holtmann899e1072013-10-14 09:55:32 -07004633 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004634 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4635 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004636
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004637 hci_dev_lock(hdev);
4638
4639 hdev->le_scan_interval = interval;
4640 hdev->le_scan_window = window;
4641
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004642 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4643 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004644
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004645 /* If background scan is running, restart it so new parameters are
4646 * loaded.
4647 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004648 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004649 hdev->discovery.state == DISCOVERY_STOPPED) {
4650 struct hci_request req;
4651
4652 hci_req_init(&req, hdev);
4653
4654 hci_req_add_le_scan_disable(&req);
4655 hci_req_add_le_passive_scan(&req);
4656
4657 hci_req_run(&req, NULL);
4658 }
4659
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004660 hci_dev_unlock(hdev);
4661
4662 return err;
4663}
4664
Marcel Holtmann1904a852015-01-11 13:50:44 -08004665static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4666 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004667{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004668 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004669
4670 BT_DBG("status 0x%02x", status);
4671
4672 hci_dev_lock(hdev);
4673
Johan Hedberg333ae952015-03-17 13:48:47 +02004674 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004675 if (!cmd)
4676 goto unlock;
4677
4678 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004679 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4680 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004681 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004682 struct mgmt_mode *cp = cmd->param;
4683
4684 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004685 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004686 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004687 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004688
Johan Hedberg33e38b32013-03-15 17:07:05 -05004689 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4690 new_settings(hdev, cmd->sk);
4691 }
4692
4693 mgmt_pending_remove(cmd);
4694
4695unlock:
4696 hci_dev_unlock(hdev);
4697}
4698
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004699static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004700 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004701{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004702 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004703 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004704 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004705 int err;
4706
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004707 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004708
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004709 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004710 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004711 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4712 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004713
Johan Hedberga7e80f22013-01-09 16:05:19 +02004714 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004715 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4716 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004717
Antti Julkuf6422ec2011-06-22 13:11:56 +03004718 hci_dev_lock(hdev);
4719
Johan Hedberg333ae952015-03-17 13:48:47 +02004720 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004721 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4722 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004723 goto unlock;
4724 }
4725
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004726 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004727 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4728 hdev);
4729 goto unlock;
4730 }
4731
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004732 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004733 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004734 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4735 hdev);
4736 new_settings(hdev, sk);
4737 goto unlock;
4738 }
4739
Johan Hedberg33e38b32013-03-15 17:07:05 -05004740 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4741 data, len);
4742 if (!cmd) {
4743 err = -ENOMEM;
4744 goto unlock;
4745 }
4746
4747 hci_req_init(&req, hdev);
4748
Johan Hedberg406d7802013-03-15 17:07:09 -05004749 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004750
4751 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004752 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004753 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4754 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004755 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004756 }
4757
Johan Hedberg33e38b32013-03-15 17:07:05 -05004758unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004759 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004760
Antti Julkuf6422ec2011-06-22 13:11:56 +03004761 return err;
4762}
4763
Marcel Holtmann1904a852015-01-11 13:50:44 -08004764static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004765{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004766 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004767
4768 BT_DBG("status 0x%02x", status);
4769
4770 hci_dev_lock(hdev);
4771
Johan Hedberg333ae952015-03-17 13:48:47 +02004772 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004773 if (!cmd)
4774 goto unlock;
4775
4776 if (status) {
4777 u8 mgmt_err = mgmt_status(status);
4778
4779 /* We need to restore the flag if related HCI commands
4780 * failed.
4781 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004782 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004783
Johan Hedberga69e8372015-03-06 21:08:53 +02004784 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004785 } else {
4786 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4787 new_settings(hdev, cmd->sk);
4788 }
4789
4790 mgmt_pending_remove(cmd);
4791
4792unlock:
4793 hci_dev_unlock(hdev);
4794}
4795
4796static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4797{
4798 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004799 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004800 struct hci_request req;
4801 int err;
4802
4803 BT_DBG("request for %s", hdev->name);
4804
4805 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004806 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4807 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004808
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004809 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004810 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4811 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004812
4813 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004814 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4815 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004816
4817 hci_dev_lock(hdev);
4818
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004819 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004820 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4821 goto unlock;
4822 }
4823
4824 if (!hdev_is_powered(hdev)) {
4825 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004826 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4827 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4828 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4829 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4830 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004831 }
4832
Marcel Holtmannce05d602015-03-13 02:11:03 -07004833 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004834
4835 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4836 if (err < 0)
4837 goto unlock;
4838
4839 err = new_settings(hdev, sk);
4840 goto unlock;
4841 }
4842
4843 /* Reject disabling when powered on */
4844 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004845 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4846 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004847 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004848 } else {
4849 /* When configuring a dual-mode controller to operate
4850 * with LE only and using a static address, then switching
4851 * BR/EDR back on is not allowed.
4852 *
4853 * Dual-mode controllers shall operate with the public
4854 * address as its identity address for BR/EDR and LE. So
4855 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004856 *
4857 * The same restrictions applies when secure connections
4858 * has been enabled. For BR/EDR this is a controller feature
4859 * while for LE it is a host stack feature. This means that
4860 * switching BR/EDR back on when secure connections has been
4861 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004862 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004863 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004864 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004865 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004866 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4867 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004868 goto unlock;
4869 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004870 }
4871
Johan Hedberg333ae952015-03-17 13:48:47 +02004872 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004873 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4874 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004875 goto unlock;
4876 }
4877
4878 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4879 if (!cmd) {
4880 err = -ENOMEM;
4881 goto unlock;
4882 }
4883
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004884 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03004885 * generates the correct flags.
4886 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004887 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004888
4889 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004890
Johan Hedberg432df052014-08-01 11:13:31 +03004891 write_fast_connectable(&req, false);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02004892 __hci_update_page_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004893
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004894 /* Since only the advertising data flags will change, there
4895 * is no need to update the scan response data.
4896 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004897 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004898
Johan Hedberg0663ca22013-10-02 13:43:14 +03004899 err = hci_req_run(&req, set_bredr_complete);
4900 if (err < 0)
4901 mgmt_pending_remove(cmd);
4902
4903unlock:
4904 hci_dev_unlock(hdev);
4905 return err;
4906}
4907
Johan Hedberga1443f52015-01-23 15:42:46 +02004908static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4909{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004910 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004911 struct mgmt_mode *cp;
4912
4913 BT_DBG("%s status %u", hdev->name, status);
4914
4915 hci_dev_lock(hdev);
4916
Johan Hedberg333ae952015-03-17 13:48:47 +02004917 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004918 if (!cmd)
4919 goto unlock;
4920
4921 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004922 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4923 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004924 goto remove;
4925 }
4926
4927 cp = cmd->param;
4928
4929 switch (cp->val) {
4930 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004931 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4932 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004933 break;
4934 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004935 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004936 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004937 break;
4938 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004939 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4940 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004941 break;
4942 }
4943
4944 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4945 new_settings(hdev, cmd->sk);
4946
4947remove:
4948 mgmt_pending_remove(cmd);
4949unlock:
4950 hci_dev_unlock(hdev);
4951}
4952
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004953static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4954 void *data, u16 len)
4955{
4956 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004957 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004958 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004959 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004960 int err;
4961
4962 BT_DBG("request for %s", hdev->name);
4963
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004964 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004965 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004966 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4967 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004968
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004969 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004970 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004971 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004972 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4973 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004974
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004975 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004976 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004977 MGMT_STATUS_INVALID_PARAMS);
4978
4979 hci_dev_lock(hdev);
4980
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004981 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004982 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004983 bool changed;
4984
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004985 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004986 changed = !hci_dev_test_and_set_flag(hdev,
4987 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004988 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004989 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004990 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004991 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004992 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004993 changed = hci_dev_test_and_clear_flag(hdev,
4994 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004995 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004996 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004997
4998 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4999 if (err < 0)
5000 goto failed;
5001
5002 if (changed)
5003 err = new_settings(hdev, sk);
5004
5005 goto failed;
5006 }
5007
Johan Hedberg333ae952015-03-17 13:48:47 +02005008 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005009 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5010 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005011 goto failed;
5012 }
5013
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005014 val = !!cp->val;
5015
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005016 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5017 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005018 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5019 goto failed;
5020 }
5021
5022 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
5023 if (!cmd) {
5024 err = -ENOMEM;
5025 goto failed;
5026 }
5027
Johan Hedberga1443f52015-01-23 15:42:46 +02005028 hci_req_init(&req, hdev);
5029 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
5030 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005031 if (err < 0) {
5032 mgmt_pending_remove(cmd);
5033 goto failed;
5034 }
5035
5036failed:
5037 hci_dev_unlock(hdev);
5038 return err;
5039}
5040
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005041static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
5042 void *data, u16 len)
5043{
5044 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03005045 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005046 int err;
5047
5048 BT_DBG("request for %s", hdev->name);
5049
Johan Hedbergb97109792014-06-24 14:00:28 +03005050 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005051 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
5052 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005053
5054 hci_dev_lock(hdev);
5055
5056 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07005057 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005058 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005059 changed = hci_dev_test_and_clear_flag(hdev,
5060 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005061
Johan Hedbergb97109792014-06-24 14:00:28 +03005062 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07005063 use_changed = !hci_dev_test_and_set_flag(hdev,
5064 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005065 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005066 use_changed = hci_dev_test_and_clear_flag(hdev,
5067 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005068
5069 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005070 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03005071 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
5072 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
5073 sizeof(mode), &mode);
5074 }
5075
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005076 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
5077 if (err < 0)
5078 goto unlock;
5079
5080 if (changed)
5081 err = new_settings(hdev, sk);
5082
5083unlock:
5084 hci_dev_unlock(hdev);
5085 return err;
5086}
5087
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005088static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5089 u16 len)
5090{
5091 struct mgmt_cp_set_privacy *cp = cp_data;
5092 bool changed;
5093 int err;
5094
5095 BT_DBG("request for %s", hdev->name);
5096
5097 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005098 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5099 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005100
5101 if (cp->privacy != 0x00 && cp->privacy != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005102 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5103 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005104
5105 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005106 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5107 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005108
5109 hci_dev_lock(hdev);
5110
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005111 /* If user space supports this command it is also expected to
5112 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
5113 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005114 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005115
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005116 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005117 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005118 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005119 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005120 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005121 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005122 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005123 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005124 }
5125
5126 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
5127 if (err < 0)
5128 goto unlock;
5129
5130 if (changed)
5131 err = new_settings(hdev, sk);
5132
5133unlock:
5134 hci_dev_unlock(hdev);
5135 return err;
5136}
5137
Johan Hedberg41edf162014-02-18 10:19:35 +02005138static bool irk_is_valid(struct mgmt_irk_info *irk)
5139{
5140 switch (irk->addr.type) {
5141 case BDADDR_LE_PUBLIC:
5142 return true;
5143
5144 case BDADDR_LE_RANDOM:
5145 /* Two most significant bits shall be set */
5146 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5147 return false;
5148 return true;
5149 }
5150
5151 return false;
5152}
5153
5154static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5155 u16 len)
5156{
5157 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005158 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5159 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005160 u16 irk_count, expected_len;
5161 int i, err;
5162
5163 BT_DBG("request for %s", hdev->name);
5164
5165 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005166 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5167 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005168
5169 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005170 if (irk_count > max_irk_count) {
5171 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005172 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5173 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005174 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005175
5176 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
5177 if (expected_len != len) {
5178 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02005179 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005180 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5181 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005182 }
5183
5184 BT_DBG("%s irk_count %u", hdev->name, irk_count);
5185
5186 for (i = 0; i < irk_count; i++) {
5187 struct mgmt_irk_info *key = &cp->irks[i];
5188
5189 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005190 return mgmt_cmd_status(sk, hdev->id,
5191 MGMT_OP_LOAD_IRKS,
5192 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005193 }
5194
5195 hci_dev_lock(hdev);
5196
5197 hci_smp_irks_clear(hdev);
5198
5199 for (i = 0; i < irk_count; i++) {
5200 struct mgmt_irk_info *irk = &cp->irks[i];
5201 u8 addr_type;
5202
5203 if (irk->addr.type == BDADDR_LE_PUBLIC)
5204 addr_type = ADDR_LE_DEV_PUBLIC;
5205 else
5206 addr_type = ADDR_LE_DEV_RANDOM;
5207
5208 hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
5209 BDADDR_ANY);
5210 }
5211
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005212 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005213
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005214 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005215
5216 hci_dev_unlock(hdev);
5217
5218 return err;
5219}
5220
Johan Hedberg3f706b72013-01-20 14:27:16 +02005221static bool ltk_is_valid(struct mgmt_ltk_info *key)
5222{
5223 if (key->master != 0x00 && key->master != 0x01)
5224 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005225
5226 switch (key->addr.type) {
5227 case BDADDR_LE_PUBLIC:
5228 return true;
5229
5230 case BDADDR_LE_RANDOM:
5231 /* Two most significant bits shall be set */
5232 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5233 return false;
5234 return true;
5235 }
5236
5237 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005238}
5239
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005240static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005241 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005242{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005243 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005244 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5245 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005246 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005247 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005248
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005249 BT_DBG("request for %s", hdev->name);
5250
5251 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005252 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5253 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005254
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005255 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005256 if (key_count > max_key_count) {
5257 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005258 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5259 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005260 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005261
5262 expected_len = sizeof(*cp) + key_count *
5263 sizeof(struct mgmt_ltk_info);
5264 if (expected_len != len) {
5265 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02005266 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005267 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5268 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005269 }
5270
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005271 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005272
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005273 for (i = 0; i < key_count; i++) {
5274 struct mgmt_ltk_info *key = &cp->keys[i];
5275
Johan Hedberg3f706b72013-01-20 14:27:16 +02005276 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005277 return mgmt_cmd_status(sk, hdev->id,
5278 MGMT_OP_LOAD_LONG_TERM_KEYS,
5279 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005280 }
5281
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005282 hci_dev_lock(hdev);
5283
5284 hci_smp_ltks_clear(hdev);
5285
5286 for (i = 0; i < key_count; i++) {
5287 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedbergd7b25452014-05-23 13:19:53 +03005288 u8 type, addr_type, authenticated;
Marcel Holtmann79d95a12013-10-13 03:57:38 -07005289
5290 if (key->addr.type == BDADDR_LE_PUBLIC)
5291 addr_type = ADDR_LE_DEV_PUBLIC;
5292 else
5293 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005294
Johan Hedberg61b43352014-05-29 19:36:53 +03005295 switch (key->type) {
5296 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005297 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005298 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005299 break;
5300 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005301 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005302 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005303 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005304 case MGMT_LTK_P256_UNAUTH:
5305 authenticated = 0x00;
5306 type = SMP_LTK_P256;
5307 break;
5308 case MGMT_LTK_P256_AUTH:
5309 authenticated = 0x01;
5310 type = SMP_LTK_P256;
5311 break;
5312 case MGMT_LTK_P256_DEBUG:
5313 authenticated = 0x00;
5314 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03005315 default:
5316 continue;
5317 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005318
Johan Hedberg35d70272014-02-19 14:57:47 +02005319 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type,
Johan Hedbergd7b25452014-05-23 13:19:53 +03005320 authenticated, key->val, key->enc_size, key->ediv,
Johan Hedberg35d70272014-02-19 14:57:47 +02005321 key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005322 }
5323
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005324 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005325 NULL, 0);
5326
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005327 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005328
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005329 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005330}
5331
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005332static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005333{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005334 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005335 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005336 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005337
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005338 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005339
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005340 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005341 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005342 rp.tx_power = conn->tx_power;
5343 rp.max_tx_power = conn->max_tx_power;
5344 } else {
5345 rp.rssi = HCI_RSSI_INVALID;
5346 rp.tx_power = HCI_TX_POWER_INVALID;
5347 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005348 }
5349
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005350 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5351 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005352
5353 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005354 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005355
5356 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005357}
5358
Marcel Holtmann1904a852015-01-11 13:50:44 -08005359static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5360 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005361{
5362 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005363 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005364 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005365 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005366 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005367
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005368 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005369
5370 hci_dev_lock(hdev);
5371
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005372 /* Commands sent in request are either Read RSSI or Read Transmit Power
5373 * Level so we check which one was last sent to retrieve connection
5374 * handle. Both commands have handle as first parameter so it's safe to
5375 * cast data on the same command struct.
5376 *
5377 * First command sent is always Read RSSI and we fail only if it fails.
5378 * In other case we simply override error to indicate success as we
5379 * already remembered if TX power value is actually valid.
5380 */
5381 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5382 if (!cp) {
5383 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005384 status = MGMT_STATUS_SUCCESS;
5385 } else {
5386 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005387 }
5388
5389 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005390 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005391 goto unlock;
5392 }
5393
5394 handle = __le16_to_cpu(cp->handle);
5395 conn = hci_conn_hash_lookup_handle(hdev, handle);
5396 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005397 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005398 goto unlock;
5399 }
5400
Johan Hedberg333ae952015-03-17 13:48:47 +02005401 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005402 if (!cmd)
5403 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005404
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005405 cmd->cmd_complete(cmd, status);
5406 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005407
5408unlock:
5409 hci_dev_unlock(hdev);
5410}
5411
5412static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5413 u16 len)
5414{
5415 struct mgmt_cp_get_conn_info *cp = data;
5416 struct mgmt_rp_get_conn_info rp;
5417 struct hci_conn *conn;
5418 unsigned long conn_info_age;
5419 int err = 0;
5420
5421 BT_DBG("%s", hdev->name);
5422
5423 memset(&rp, 0, sizeof(rp));
5424 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5425 rp.addr.type = cp->addr.type;
5426
5427 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005428 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5429 MGMT_STATUS_INVALID_PARAMS,
5430 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005431
5432 hci_dev_lock(hdev);
5433
5434 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005435 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5436 MGMT_STATUS_NOT_POWERED, &rp,
5437 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005438 goto unlock;
5439 }
5440
5441 if (cp->addr.type == BDADDR_BREDR)
5442 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5443 &cp->addr.bdaddr);
5444 else
5445 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5446
5447 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005448 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5449 MGMT_STATUS_NOT_CONNECTED, &rp,
5450 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005451 goto unlock;
5452 }
5453
Johan Hedberg333ae952015-03-17 13:48:47 +02005454 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005455 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5456 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005457 goto unlock;
5458 }
5459
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005460 /* To avoid client trying to guess when to poll again for information we
5461 * calculate conn info age as random value between min/max set in hdev.
5462 */
5463 conn_info_age = hdev->conn_info_min_age +
5464 prandom_u32_max(hdev->conn_info_max_age -
5465 hdev->conn_info_min_age);
5466
5467 /* Query controller to refresh cached values if they are too old or were
5468 * never read.
5469 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005470 if (time_after(jiffies, conn->conn_info_timestamp +
5471 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005472 !conn->conn_info_timestamp) {
5473 struct hci_request req;
5474 struct hci_cp_read_tx_power req_txp_cp;
5475 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005476 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005477
5478 hci_req_init(&req, hdev);
5479 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5480 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5481 &req_rssi_cp);
5482
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005483 /* For LE links TX power does not change thus we don't need to
5484 * query for it once value is known.
5485 */
5486 if (!bdaddr_type_is_le(cp->addr.type) ||
5487 conn->tx_power == HCI_TX_POWER_INVALID) {
5488 req_txp_cp.handle = cpu_to_le16(conn->handle);
5489 req_txp_cp.type = 0x00;
5490 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5491 sizeof(req_txp_cp), &req_txp_cp);
5492 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005493
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005494 /* Max TX power needs to be read only once per connection */
5495 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5496 req_txp_cp.handle = cpu_to_le16(conn->handle);
5497 req_txp_cp.type = 0x01;
5498 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5499 sizeof(req_txp_cp), &req_txp_cp);
5500 }
5501
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005502 err = hci_req_run(&req, conn_info_refresh_complete);
5503 if (err < 0)
5504 goto unlock;
5505
5506 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5507 data, len);
5508 if (!cmd) {
5509 err = -ENOMEM;
5510 goto unlock;
5511 }
5512
5513 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005514 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005515 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005516
5517 conn->conn_info_timestamp = jiffies;
5518 } else {
5519 /* Cache is valid, just reply with values cached in hci_conn */
5520 rp.rssi = conn->rssi;
5521 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005522 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005523
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005524 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5525 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005526 }
5527
5528unlock:
5529 hci_dev_unlock(hdev);
5530 return err;
5531}
5532
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005533static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005534{
5535 struct hci_conn *conn = cmd->user_data;
5536 struct mgmt_rp_get_clock_info rp;
5537 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005538 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005539
5540 memset(&rp, 0, sizeof(rp));
5541 memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
5542
5543 if (status)
5544 goto complete;
5545
5546 hdev = hci_dev_get(cmd->index);
5547 if (hdev) {
5548 rp.local_clock = cpu_to_le32(hdev->clock);
5549 hci_dev_put(hdev);
5550 }
5551
5552 if (conn) {
5553 rp.piconet_clock = cpu_to_le32(conn->clock);
5554 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5555 }
5556
5557complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005558 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5559 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005560
5561 if (conn) {
5562 hci_conn_drop(conn);
5563 hci_conn_put(conn);
5564 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005565
5566 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005567}
5568
Marcel Holtmann1904a852015-01-11 13:50:44 -08005569static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005570{
Johan Hedberg95868422014-06-28 17:54:07 +03005571 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005572 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005573 struct hci_conn *conn;
5574
5575 BT_DBG("%s status %u", hdev->name, status);
5576
5577 hci_dev_lock(hdev);
5578
5579 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5580 if (!hci_cp)
5581 goto unlock;
5582
5583 if (hci_cp->which) {
5584 u16 handle = __le16_to_cpu(hci_cp->handle);
5585 conn = hci_conn_hash_lookup_handle(hdev, handle);
5586 } else {
5587 conn = NULL;
5588 }
5589
Johan Hedberg333ae952015-03-17 13:48:47 +02005590 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005591 if (!cmd)
5592 goto unlock;
5593
Johan Hedberg69487372014-12-05 13:36:07 +02005594 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005595 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005596
5597unlock:
5598 hci_dev_unlock(hdev);
5599}
5600
5601static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5602 u16 len)
5603{
5604 struct mgmt_cp_get_clock_info *cp = data;
5605 struct mgmt_rp_get_clock_info rp;
5606 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005607 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005608 struct hci_request req;
5609 struct hci_conn *conn;
5610 int err;
5611
5612 BT_DBG("%s", hdev->name);
5613
5614 memset(&rp, 0, sizeof(rp));
5615 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5616 rp.addr.type = cp->addr.type;
5617
5618 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005619 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5620 MGMT_STATUS_INVALID_PARAMS,
5621 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005622
5623 hci_dev_lock(hdev);
5624
5625 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005626 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5627 MGMT_STATUS_NOT_POWERED, &rp,
5628 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005629 goto unlock;
5630 }
5631
5632 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5633 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5634 &cp->addr.bdaddr);
5635 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005636 err = mgmt_cmd_complete(sk, hdev->id,
5637 MGMT_OP_GET_CLOCK_INFO,
5638 MGMT_STATUS_NOT_CONNECTED,
5639 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005640 goto unlock;
5641 }
5642 } else {
5643 conn = NULL;
5644 }
5645
5646 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5647 if (!cmd) {
5648 err = -ENOMEM;
5649 goto unlock;
5650 }
5651
Johan Hedberg69487372014-12-05 13:36:07 +02005652 cmd->cmd_complete = clock_info_cmd_complete;
5653
Johan Hedberg95868422014-06-28 17:54:07 +03005654 hci_req_init(&req, hdev);
5655
5656 memset(&hci_cp, 0, sizeof(hci_cp));
5657 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5658
5659 if (conn) {
5660 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005661 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005662
5663 hci_cp.handle = cpu_to_le16(conn->handle);
5664 hci_cp.which = 0x01; /* Piconet clock */
5665 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5666 }
5667
5668 err = hci_req_run(&req, get_clock_info_complete);
5669 if (err < 0)
5670 mgmt_pending_remove(cmd);
5671
5672unlock:
5673 hci_dev_unlock(hdev);
5674 return err;
5675}
5676
Johan Hedberg5a154e62014-12-19 22:26:02 +02005677static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5678{
5679 struct hci_conn *conn;
5680
5681 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5682 if (!conn)
5683 return false;
5684
5685 if (conn->dst_type != type)
5686 return false;
5687
5688 if (conn->state != BT_CONNECTED)
5689 return false;
5690
5691 return true;
5692}
5693
5694/* This function requires the caller holds hdev->lock */
5695static int hci_conn_params_set(struct hci_request *req, bdaddr_t *addr,
5696 u8 addr_type, u8 auto_connect)
5697{
5698 struct hci_dev *hdev = req->hdev;
5699 struct hci_conn_params *params;
5700
5701 params = hci_conn_params_add(hdev, addr, addr_type);
5702 if (!params)
5703 return -EIO;
5704
5705 if (params->auto_connect == auto_connect)
5706 return 0;
5707
5708 list_del_init(&params->action);
5709
5710 switch (auto_connect) {
5711 case HCI_AUTO_CONN_DISABLED:
5712 case HCI_AUTO_CONN_LINK_LOSS:
5713 __hci_update_background_scan(req);
5714 break;
5715 case HCI_AUTO_CONN_REPORT:
5716 list_add(&params->action, &hdev->pend_le_reports);
5717 __hci_update_background_scan(req);
5718 break;
5719 case HCI_AUTO_CONN_DIRECT:
5720 case HCI_AUTO_CONN_ALWAYS:
5721 if (!is_connected(hdev, addr, addr_type)) {
5722 list_add(&params->action, &hdev->pend_le_conns);
5723 __hci_update_background_scan(req);
5724 }
5725 break;
5726 }
5727
5728 params->auto_connect = auto_connect;
5729
5730 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5731 auto_connect);
5732
5733 return 0;
5734}
5735
Marcel Holtmann8afef092014-06-29 22:28:34 +02005736static void device_added(struct sock *sk, struct hci_dev *hdev,
5737 bdaddr_t *bdaddr, u8 type, u8 action)
5738{
5739 struct mgmt_ev_device_added ev;
5740
5741 bacpy(&ev.addr.bdaddr, bdaddr);
5742 ev.addr.type = type;
5743 ev.action = action;
5744
5745 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5746}
5747
Marcel Holtmann1904a852015-01-11 13:50:44 -08005748static void add_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg5a154e62014-12-19 22:26:02 +02005749{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005750 struct mgmt_pending_cmd *cmd;
Johan Hedberg5a154e62014-12-19 22:26:02 +02005751
5752 BT_DBG("status 0x%02x", status);
5753
5754 hci_dev_lock(hdev);
5755
Johan Hedberg333ae952015-03-17 13:48:47 +02005756 cmd = pending_find(MGMT_OP_ADD_DEVICE, hdev);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005757 if (!cmd)
5758 goto unlock;
5759
5760 cmd->cmd_complete(cmd, mgmt_status(status));
5761 mgmt_pending_remove(cmd);
5762
5763unlock:
5764 hci_dev_unlock(hdev);
5765}
5766
Marcel Holtmann2faade52014-06-29 19:44:03 +02005767static int add_device(struct sock *sk, struct hci_dev *hdev,
5768 void *data, u16 len)
5769{
5770 struct mgmt_cp_add_device *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005771 struct mgmt_pending_cmd *cmd;
Johan Hedberg5a154e62014-12-19 22:26:02 +02005772 struct hci_request req;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005773 u8 auto_conn, addr_type;
5774 int err;
5775
5776 BT_DBG("%s", hdev->name);
5777
Johan Hedberg66593582014-07-09 12:59:14 +03005778 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005779 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005780 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5781 MGMT_STATUS_INVALID_PARAMS,
5782 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005783
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005784 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005785 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5786 MGMT_STATUS_INVALID_PARAMS,
5787 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005788
Johan Hedberg5a154e62014-12-19 22:26:02 +02005789 hci_req_init(&req, hdev);
5790
Marcel Holtmann2faade52014-06-29 19:44:03 +02005791 hci_dev_lock(hdev);
5792
Johan Hedberg5a154e62014-12-19 22:26:02 +02005793 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_DEVICE, hdev, data, len);
5794 if (!cmd) {
5795 err = -ENOMEM;
5796 goto unlock;
5797 }
5798
5799 cmd->cmd_complete = addr_cmd_complete;
5800
Johan Hedberg66593582014-07-09 12:59:14 +03005801 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005802 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005803 if (cp->action != 0x01) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005804 err = cmd->cmd_complete(cmd,
5805 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005806 mgmt_pending_remove(cmd);
Johan Hedberg66593582014-07-09 12:59:14 +03005807 goto unlock;
5808 }
5809
5810 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5811 cp->addr.type);
5812 if (err)
5813 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005814
Johan Hedberg5a154e62014-12-19 22:26:02 +02005815 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03005816
Johan Hedberg66593582014-07-09 12:59:14 +03005817 goto added;
5818 }
5819
Marcel Holtmann2faade52014-06-29 19:44:03 +02005820 if (cp->addr.type == BDADDR_LE_PUBLIC)
5821 addr_type = ADDR_LE_DEV_PUBLIC;
5822 else
5823 addr_type = ADDR_LE_DEV_RANDOM;
5824
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005825 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005826 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005827 else if (cp->action == 0x01)
5828 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005829 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005830 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005831
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005832 /* If the connection parameters don't exist for this device,
5833 * they will be created and configured with defaults.
5834 */
Johan Hedberg5a154e62014-12-19 22:26:02 +02005835 if (hci_conn_params_set(&req, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005836 auto_conn) < 0) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005837 err = cmd->cmd_complete(cmd, MGMT_STATUS_FAILED);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005838 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005839 goto unlock;
5840 }
5841
Johan Hedberg66593582014-07-09 12:59:14 +03005842added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005843 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5844
Johan Hedberg5a154e62014-12-19 22:26:02 +02005845 err = hci_req_run(&req, add_device_complete);
5846 if (err < 0) {
5847 /* ENODATA means no HCI commands were needed (e.g. if
5848 * the adapter is powered off).
5849 */
Johan Hedberg9df74652014-12-19 22:26:03 +02005850 if (err == -ENODATA)
5851 err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005852 mgmt_pending_remove(cmd);
5853 }
Marcel Holtmann2faade52014-06-29 19:44:03 +02005854
5855unlock:
5856 hci_dev_unlock(hdev);
5857 return err;
5858}
5859
Marcel Holtmann8afef092014-06-29 22:28:34 +02005860static void device_removed(struct sock *sk, struct hci_dev *hdev,
5861 bdaddr_t *bdaddr, u8 type)
5862{
5863 struct mgmt_ev_device_removed ev;
5864
5865 bacpy(&ev.addr.bdaddr, bdaddr);
5866 ev.addr.type = type;
5867
5868 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5869}
5870
Marcel Holtmann1904a852015-01-11 13:50:44 -08005871static void remove_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005872{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005873 struct mgmt_pending_cmd *cmd;
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005874
5875 BT_DBG("status 0x%02x", status);
5876
5877 hci_dev_lock(hdev);
5878
Johan Hedberg333ae952015-03-17 13:48:47 +02005879 cmd = pending_find(MGMT_OP_REMOVE_DEVICE, hdev);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005880 if (!cmd)
5881 goto unlock;
5882
5883 cmd->cmd_complete(cmd, mgmt_status(status));
5884 mgmt_pending_remove(cmd);
5885
5886unlock:
5887 hci_dev_unlock(hdev);
5888}
5889
Marcel Holtmann2faade52014-06-29 19:44:03 +02005890static int remove_device(struct sock *sk, struct hci_dev *hdev,
5891 void *data, u16 len)
5892{
5893 struct mgmt_cp_remove_device *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005894 struct mgmt_pending_cmd *cmd;
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005895 struct hci_request req;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005896 int err;
5897
5898 BT_DBG("%s", hdev->name);
5899
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005900 hci_req_init(&req, hdev);
5901
Marcel Holtmann2faade52014-06-29 19:44:03 +02005902 hci_dev_lock(hdev);
5903
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005904 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_DEVICE, hdev, data, len);
5905 if (!cmd) {
5906 err = -ENOMEM;
5907 goto unlock;
5908 }
5909
5910 cmd->cmd_complete = addr_cmd_complete;
5911
Marcel Holtmann2faade52014-06-29 19:44:03 +02005912 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005913 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005914 u8 addr_type;
5915
Johan Hedberg66593582014-07-09 12:59:14 +03005916 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005917 err = cmd->cmd_complete(cmd,
5918 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005919 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005920 goto unlock;
5921 }
5922
Johan Hedberg66593582014-07-09 12:59:14 +03005923 if (cp->addr.type == BDADDR_BREDR) {
5924 err = hci_bdaddr_list_del(&hdev->whitelist,
5925 &cp->addr.bdaddr,
5926 cp->addr.type);
5927 if (err) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005928 err = cmd->cmd_complete(cmd,
5929 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005930 mgmt_pending_remove(cmd);
Johan Hedberg66593582014-07-09 12:59:14 +03005931 goto unlock;
5932 }
5933
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005934 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03005935
Johan Hedberg66593582014-07-09 12:59:14 +03005936 device_removed(sk, hdev, &cp->addr.bdaddr,
5937 cp->addr.type);
5938 goto complete;
5939 }
5940
Marcel Holtmann2faade52014-06-29 19:44:03 +02005941 if (cp->addr.type == BDADDR_LE_PUBLIC)
5942 addr_type = ADDR_LE_DEV_PUBLIC;
5943 else
5944 addr_type = ADDR_LE_DEV_RANDOM;
5945
Johan Hedbergc71593d2014-07-02 17:37:28 +03005946 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5947 addr_type);
5948 if (!params) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005949 err = cmd->cmd_complete(cmd,
5950 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005951 mgmt_pending_remove(cmd);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005952 goto unlock;
5953 }
5954
5955 if (params->auto_connect == HCI_AUTO_CONN_DISABLED) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005956 err = cmd->cmd_complete(cmd,
5957 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005958 mgmt_pending_remove(cmd);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005959 goto unlock;
5960 }
5961
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005962 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005963 list_del(&params->list);
5964 kfree(params);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005965 __hci_update_background_scan(&req);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005966
5967 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005968 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005969 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005970 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005971
Marcel Holtmann2faade52014-06-29 19:44:03 +02005972 if (cp->addr.type) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005973 err = cmd->cmd_complete(cmd,
5974 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005975 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005976 goto unlock;
5977 }
5978
Johan Hedberg66593582014-07-09 12:59:14 +03005979 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5980 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5981 list_del(&b->list);
5982 kfree(b);
5983 }
5984
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005985 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03005986
Johan Hedberg19de0822014-07-06 13:06:51 +03005987 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5988 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5989 continue;
5990 device_removed(sk, hdev, &p->addr, p->addr_type);
5991 list_del(&p->action);
5992 list_del(&p->list);
5993 kfree(p);
5994 }
5995
5996 BT_DBG("All LE connection parameters were removed");
5997
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005998 __hci_update_background_scan(&req);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005999 }
6000
Johan Hedberg66593582014-07-09 12:59:14 +03006001complete:
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006002 err = hci_req_run(&req, remove_device_complete);
6003 if (err < 0) {
6004 /* ENODATA means no HCI commands were needed (e.g. if
6005 * the adapter is powered off).
6006 */
Johan Hedberg9df74652014-12-19 22:26:03 +02006007 if (err == -ENODATA)
6008 err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006009 mgmt_pending_remove(cmd);
6010 }
Marcel Holtmann2faade52014-06-29 19:44:03 +02006011
6012unlock:
6013 hci_dev_unlock(hdev);
6014 return err;
6015}
6016
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006017static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
6018 u16 len)
6019{
6020 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006021 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
6022 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006023 u16 param_count, expected_len;
6024 int i;
6025
6026 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006027 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6028 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006029
6030 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006031 if (param_count > max_param_count) {
6032 BT_ERR("load_conn_param: too big param_count value %u",
6033 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006034 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6035 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006036 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006037
6038 expected_len = sizeof(*cp) + param_count *
6039 sizeof(struct mgmt_conn_param);
6040 if (expected_len != len) {
6041 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
6042 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006043 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6044 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006045 }
6046
6047 BT_DBG("%s param_count %u", hdev->name, param_count);
6048
6049 hci_dev_lock(hdev);
6050
6051 hci_conn_params_clear_disabled(hdev);
6052
6053 for (i = 0; i < param_count; i++) {
6054 struct mgmt_conn_param *param = &cp->params[i];
6055 struct hci_conn_params *hci_param;
6056 u16 min, max, latency, timeout;
6057 u8 addr_type;
6058
6059 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
6060 param->addr.type);
6061
6062 if (param->addr.type == BDADDR_LE_PUBLIC) {
6063 addr_type = ADDR_LE_DEV_PUBLIC;
6064 } else if (param->addr.type == BDADDR_LE_RANDOM) {
6065 addr_type = ADDR_LE_DEV_RANDOM;
6066 } else {
6067 BT_ERR("Ignoring invalid connection parameters");
6068 continue;
6069 }
6070
6071 min = le16_to_cpu(param->min_interval);
6072 max = le16_to_cpu(param->max_interval);
6073 latency = le16_to_cpu(param->latency);
6074 timeout = le16_to_cpu(param->timeout);
6075
6076 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6077 min, max, latency, timeout);
6078
6079 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
6080 BT_ERR("Ignoring invalid connection parameters");
6081 continue;
6082 }
6083
6084 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
6085 addr_type);
6086 if (!hci_param) {
6087 BT_ERR("Failed to add connection parameters");
6088 continue;
6089 }
6090
6091 hci_param->conn_min_interval = min;
6092 hci_param->conn_max_interval = max;
6093 hci_param->conn_latency = latency;
6094 hci_param->supervision_timeout = timeout;
6095 }
6096
6097 hci_dev_unlock(hdev);
6098
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006099 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
6100 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006101}
6102
Marcel Holtmanndbece372014-07-04 18:11:55 +02006103static int set_external_config(struct sock *sk, struct hci_dev *hdev,
6104 void *data, u16 len)
6105{
6106 struct mgmt_cp_set_external_config *cp = data;
6107 bool changed;
6108 int err;
6109
6110 BT_DBG("%s", hdev->name);
6111
6112 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006113 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6114 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006115
6116 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006117 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6118 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006119
6120 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02006121 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6122 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006123
6124 hci_dev_lock(hdev);
6125
6126 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07006127 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006128 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006129 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006130
6131 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
6132 if (err < 0)
6133 goto unlock;
6134
6135 if (!changed)
6136 goto unlock;
6137
Marcel Holtmannf4537c02014-07-04 19:06:23 +02006138 err = new_options(hdev, sk);
6139
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006140 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02006141 mgmt_index_removed(hdev);
Marcel Holtmannd603b762014-07-06 12:11:14 +02006142
Marcel Holtmann516018a2015-03-13 02:11:04 -07006143 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006144 hci_dev_set_flag(hdev, HCI_CONFIG);
6145 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b762014-07-06 12:11:14 +02006146
6147 queue_work(hdev->req_workqueue, &hdev->power_on);
6148 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02006149 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b762014-07-06 12:11:14 +02006150 mgmt_index_added(hdev);
6151 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02006152 }
6153
6154unlock:
6155 hci_dev_unlock(hdev);
6156 return err;
6157}
6158
Marcel Holtmann9713c172014-07-06 12:11:15 +02006159static int set_public_address(struct sock *sk, struct hci_dev *hdev,
6160 void *data, u16 len)
6161{
6162 struct mgmt_cp_set_public_address *cp = data;
6163 bool changed;
6164 int err;
6165
6166 BT_DBG("%s", hdev->name);
6167
6168 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006169 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6170 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006171
6172 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02006173 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6174 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006175
6176 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02006177 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6178 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006179
6180 hci_dev_lock(hdev);
6181
6182 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
6183 bacpy(&hdev->public_addr, &cp->bdaddr);
6184
6185 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
6186 if (err < 0)
6187 goto unlock;
6188
6189 if (!changed)
6190 goto unlock;
6191
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006192 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006193 err = new_options(hdev, sk);
6194
6195 if (is_configured(hdev)) {
6196 mgmt_index_removed(hdev);
6197
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006198 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006199
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006200 hci_dev_set_flag(hdev, HCI_CONFIG);
6201 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006202
6203 queue_work(hdev->req_workqueue, &hdev->power_on);
6204 }
6205
6206unlock:
6207 hci_dev_unlock(hdev);
6208 return err;
6209}
6210
Marcel Holtmannbea41602015-03-14 22:43:17 -07006211static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
6212 u8 data_len)
6213{
6214 eir[eir_len++] = sizeof(type) + data_len;
6215 eir[eir_len++] = type;
6216 memcpy(&eir[eir_len], data, data_len);
6217 eir_len += data_len;
6218
6219 return eir_len;
6220}
6221
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006222static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
6223 void *data, u16 data_len)
6224{
6225 struct mgmt_cp_read_local_oob_ext_data *cp = data;
6226 struct mgmt_rp_read_local_oob_ext_data *rp;
6227 size_t rp_len;
6228 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006229 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006230 int err;
6231
6232 BT_DBG("%s", hdev->name);
6233
6234 if (!hdev_is_powered(hdev))
6235 return mgmt_cmd_complete(sk, hdev->id,
6236 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6237 MGMT_STATUS_NOT_POWERED,
6238 &cp->type, sizeof(cp->type));
6239
6240 switch (cp->type) {
6241 case BIT(BDADDR_BREDR):
6242 status = mgmt_bredr_support(hdev);
6243 if (status)
6244 return mgmt_cmd_complete(sk, hdev->id,
6245 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6246 status, &cp->type,
6247 sizeof(cp->type));
6248 eir_len = 5;
6249 break;
6250 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6251 status = mgmt_le_support(hdev);
6252 if (status)
6253 return mgmt_cmd_complete(sk, hdev->id,
6254 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6255 status, &cp->type,
6256 sizeof(cp->type));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006257 eir_len = 9 + 3 + 18 + 18 + 3;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006258 break;
6259 default:
6260 return mgmt_cmd_complete(sk, hdev->id,
6261 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6262 MGMT_STATUS_INVALID_PARAMS,
6263 &cp->type, sizeof(cp->type));
6264 }
6265
6266 hci_dev_lock(hdev);
6267
6268 rp_len = sizeof(*rp) + eir_len;
6269 rp = kmalloc(rp_len, GFP_ATOMIC);
6270 if (!rp) {
6271 hci_dev_unlock(hdev);
6272 return -ENOMEM;
6273 }
6274
6275 eir_len = 0;
6276 switch (cp->type) {
6277 case BIT(BDADDR_BREDR):
6278 eir_len = eir_append_data(rp->eir, eir_len, EIR_CLASS_OF_DEV,
6279 hdev->dev_class, 3);
6280 break;
6281 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07006282 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6283 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006284 hci_dev_unlock(hdev);
6285 err = mgmt_cmd_complete(sk, hdev->id,
Marcel Holtmann5082a592015-03-16 12:39:00 -07006286 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6287 MGMT_STATUS_FAILED,
6288 &cp->type, sizeof(cp->type));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006289 goto done;
6290 }
6291
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006292 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
6293 memcpy(addr, &hdev->rpa, 6);
6294 addr[6] = 0x01;
6295 } else if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
6296 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
6297 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
6298 bacmp(&hdev->static_addr, BDADDR_ANY))) {
6299 memcpy(addr, &hdev->static_addr, 6);
6300 addr[6] = 0x01;
6301 } else {
6302 memcpy(addr, &hdev->bdaddr, 6);
6303 addr[6] = 0x00;
6304 }
6305
6306 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
6307 addr, sizeof(addr));
6308
6309 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
6310 role = 0x02;
6311 else
6312 role = 0x01;
6313
6314 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
6315 &role, sizeof(role));
6316
Marcel Holtmann5082a592015-03-16 12:39:00 -07006317 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
6318 eir_len = eir_append_data(rp->eir, eir_len,
6319 EIR_LE_SC_CONFIRM,
6320 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006321
Marcel Holtmann5082a592015-03-16 12:39:00 -07006322 eir_len = eir_append_data(rp->eir, eir_len,
6323 EIR_LE_SC_RANDOM,
6324 rand, sizeof(rand));
6325 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006326
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006327 flags = get_adv_discov_flags(hdev);
6328
6329 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
6330 flags |= LE_AD_NO_BREDR;
6331
6332 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
6333 &flags, sizeof(flags));
6334 break;
6335 }
6336
6337 rp->type = cp->type;
6338 rp->eir_len = cpu_to_le16(eir_len);
6339
6340 hci_dev_unlock(hdev);
6341
Marcel Holtmann72000df2015-03-16 16:11:21 -07006342 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
6343
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006344 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann5425f982015-03-16 16:05:44 -07006345 MGMT_STATUS_SUCCESS, rp, sizeof(*rp) + eir_len);
Marcel Holtmann72000df2015-03-16 16:11:21 -07006346 if (err < 0)
6347 goto done;
6348
6349 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6350 rp, sizeof(*rp) + eir_len,
6351 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006352
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006353done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006354 kfree(rp);
6355
6356 return err;
6357}
6358
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006359static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6360 void *data, u16 data_len)
6361{
6362 struct mgmt_rp_read_adv_features *rp;
6363 size_t rp_len;
6364 int err;
Arman Uguray24b4f382015-03-23 15:57:12 -07006365 bool instance;
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006366
6367 BT_DBG("%s", hdev->name);
6368
6369 hci_dev_lock(hdev);
6370
6371 rp_len = sizeof(*rp);
Arman Uguray24b4f382015-03-23 15:57:12 -07006372
6373 /* Currently only one instance is supported, so just add 1 to the
6374 * response length.
6375 */
6376 instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE);
6377 if (instance)
6378 rp_len++;
6379
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006380 rp = kmalloc(rp_len, GFP_ATOMIC);
6381 if (!rp) {
6382 hci_dev_unlock(hdev);
6383 return -ENOMEM;
6384 }
6385
6386 rp->supported_flags = cpu_to_le32(0);
Marcel Holtmanndc5d82a2015-03-19 17:22:25 -07006387 rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
6388 rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
Arman Uguray24b4f382015-03-23 15:57:12 -07006389 rp->max_instances = 1;
6390
6391 /* Currently only one instance is supported, so simply return the
6392 * current instance number.
6393 */
6394 if (instance) {
6395 rp->num_instances = 1;
6396 rp->instance[0] = 1;
6397 } else {
6398 rp->num_instances = 0;
6399 }
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006400
6401 hci_dev_unlock(hdev);
6402
6403 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6404 MGMT_STATUS_SUCCESS, rp, rp_len);
6405
6406 kfree(rp);
6407
6408 return err;
6409}
6410
Arman Uguray24b4f382015-03-23 15:57:12 -07006411static bool adv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *adv_data,
6412 u8 adv_data_len)
6413{
6414 u8 max_adv_len = HCI_MAX_AD_LENGTH;
6415 int i, cur_len;
6416
6417 /* TODO: Correctly reduce adv_len based on adv_flags. */
6418
6419 if (adv_data_len > max_adv_len)
6420 return false;
6421
6422 /* Make sure that adv_data is correctly formatted. */
6423 for (i = 0, cur_len = 0; i < adv_data_len; i += (cur_len + 1)) {
6424 cur_len = adv_data[i];
6425
6426 /* If the current field length would exceed the total data
6427 * length, then it's invalid.
6428 */
6429 if (i + cur_len >= adv_data_len)
6430 return false;
6431 }
6432
6433 return true;
6434}
6435
6436static void advertising_added(struct sock *sk, struct hci_dev *hdev,
6437 u8 instance)
6438{
6439 struct mgmt_ev_advertising_added ev;
6440
6441 ev.instance = instance;
6442
6443 mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk);
6444}
6445
6446static void advertising_removed(struct sock *sk, struct hci_dev *hdev,
6447 u8 instance)
6448{
6449 struct mgmt_ev_advertising_removed ev;
6450
6451 ev.instance = instance;
6452
6453 mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk);
6454}
6455
6456static void add_advertising_complete(struct hci_dev *hdev, u8 status,
6457 u16 opcode)
6458{
6459 struct mgmt_pending_cmd *cmd;
6460 struct mgmt_rp_add_advertising rp;
6461
6462 BT_DBG("status %d", status);
6463
6464 hci_dev_lock(hdev);
6465
6466 cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev);
6467
6468 if (status) {
6469 hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
6470 memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
6471 advertising_removed(cmd ? cmd->sk : NULL, hdev, 1);
6472 }
6473
6474 if (!cmd)
6475 goto unlock;
6476
6477 rp.instance = 0x01;
6478
6479 if (status)
6480 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
6481 mgmt_status(status));
6482 else
6483 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
6484 mgmt_status(status), &rp, sizeof(rp));
6485
6486 mgmt_pending_remove(cmd);
6487
6488unlock:
6489 hci_dev_unlock(hdev);
6490}
6491
6492static int add_advertising(struct sock *sk, struct hci_dev *hdev,
6493 void *data, u16 data_len)
6494{
6495 struct mgmt_cp_add_advertising *cp = data;
6496 struct mgmt_rp_add_advertising rp;
6497 u32 flags;
6498 u8 status;
6499 int err;
6500 struct mgmt_pending_cmd *cmd;
6501 struct hci_request req;
6502
6503 BT_DBG("%s", hdev->name);
6504
6505 status = mgmt_le_support(hdev);
6506 if (status)
6507 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6508 status);
6509
6510 flags = __le32_to_cpu(cp->flags);
6511
6512 /* The current implementation only supports adding one instance and
6513 * doesn't support flags.
6514 */
6515 if (cp->instance != 0x01 || flags)
6516 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6517 MGMT_STATUS_INVALID_PARAMS);
6518
6519 hci_dev_lock(hdev);
6520
6521 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
Arman Ugurayda9293352015-03-23 15:57:13 -07006522 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
Arman Uguray24b4f382015-03-23 15:57:12 -07006523 pending_find(MGMT_OP_SET_LE, hdev)) {
6524 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6525 MGMT_STATUS_BUSY);
6526 goto unlock;
6527 }
6528
6529 if (!adv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len)) {
6530 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6531 MGMT_STATUS_INVALID_PARAMS);
6532 goto unlock;
6533 }
6534
6535 hdev->adv_instance.flags = flags;
6536 hdev->adv_instance.adv_data_len = cp->adv_data_len;
6537 hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len;
6538
6539 if (cp->adv_data_len)
6540 memcpy(hdev->adv_instance.adv_data, cp->data, cp->adv_data_len);
6541
6542 if (cp->scan_rsp_len)
6543 memcpy(hdev->adv_instance.scan_rsp_data,
6544 cp->data + cp->adv_data_len, cp->scan_rsp_len);
6545
6546 if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE))
6547 advertising_added(sk, hdev, 1);
6548
6549 /* If the HCI_ADVERTISING flag is set or the device isn't powered then
6550 * we have no HCI communication to make. Simply return.
6551 */
6552 if (!hdev_is_powered(hdev) ||
6553 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
6554 rp.instance = 0x01;
6555 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
6556 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6557 goto unlock;
6558 }
6559
6560 /* We're good to go, update advertising data, parameters, and start
6561 * advertising.
6562 */
6563 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data,
6564 data_len);
6565 if (!cmd) {
6566 err = -ENOMEM;
6567 goto unlock;
6568 }
6569
6570 hci_req_init(&req, hdev);
6571
6572 update_adv_data(&req);
6573 enable_advertising(&req);
6574
6575 err = hci_req_run(&req, add_advertising_complete);
6576 if (err < 0)
6577 mgmt_pending_remove(cmd);
6578
6579unlock:
6580 hci_dev_unlock(hdev);
6581
6582 return err;
6583}
6584
Arman Ugurayda9293352015-03-23 15:57:13 -07006585static void remove_advertising_complete(struct hci_dev *hdev, u8 status,
6586 u16 opcode)
6587{
6588 struct mgmt_pending_cmd *cmd;
6589 struct mgmt_rp_remove_advertising rp;
6590
6591 BT_DBG("status %d", status);
6592
6593 hci_dev_lock(hdev);
6594
6595 /* A failure status here only means that we failed to disable
6596 * advertising. Otherwise, the advertising instance has been removed,
6597 * so report success.
6598 */
6599 cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev);
6600 if (!cmd)
6601 goto unlock;
6602
6603 rp.instance = 1;
6604
6605 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS,
6606 &rp, sizeof(rp));
6607 mgmt_pending_remove(cmd);
6608
6609unlock:
6610 hci_dev_unlock(hdev);
6611}
6612
6613static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
6614 void *data, u16 data_len)
6615{
6616 struct mgmt_cp_remove_advertising *cp = data;
6617 struct mgmt_rp_remove_advertising rp;
6618 int err;
6619 struct mgmt_pending_cmd *cmd;
6620 struct hci_request req;
6621
6622 BT_DBG("%s", hdev->name);
6623
6624 /* The current implementation only allows modifying instance no 1. A
6625 * value of 0 indicates that all instances should be cleared.
6626 */
6627 if (cp->instance > 1)
6628 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6629 MGMT_STATUS_INVALID_PARAMS);
6630
6631 hci_dev_lock(hdev);
6632
6633 if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
6634 pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
6635 pending_find(MGMT_OP_SET_LE, hdev)) {
6636 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6637 MGMT_STATUS_BUSY);
6638 goto unlock;
6639 }
6640
6641 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) {
6642 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
6643 MGMT_STATUS_INVALID_PARAMS);
6644 goto unlock;
6645 }
6646
6647 memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance));
6648
6649 advertising_removed(sk, hdev, 1);
6650
6651 hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE);
6652
6653 /* If the HCI_ADVERTISING flag is set or the device isn't powered then
6654 * we have no HCI communication to make. Simply return.
6655 */
6656 if (!hdev_is_powered(hdev) ||
6657 hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
6658 rp.instance = 1;
6659 err = mgmt_cmd_complete(sk, hdev->id,
6660 MGMT_OP_REMOVE_ADVERTISING,
6661 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
6662 goto unlock;
6663 }
6664
6665 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data,
6666 data_len);
6667 if (!cmd) {
6668 err = -ENOMEM;
6669 goto unlock;
6670 }
6671
6672 hci_req_init(&req, hdev);
6673 disable_advertising(&req);
6674
6675 err = hci_req_run(&req, remove_advertising_complete);
6676 if (err < 0)
6677 mgmt_pending_remove(cmd);
6678
6679unlock:
6680 hci_dev_unlock(hdev);
6681
6682 return err;
6683}
6684
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006685static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006686 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006687 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006688 HCI_MGMT_NO_HDEV |
6689 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006690 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006691 HCI_MGMT_NO_HDEV |
6692 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006693 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006694 HCI_MGMT_NO_HDEV |
6695 HCI_MGMT_UNTRUSTED },
6696 { read_controller_info, MGMT_READ_INFO_SIZE,
6697 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006698 { set_powered, MGMT_SETTING_SIZE },
6699 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6700 { set_connectable, MGMT_SETTING_SIZE },
6701 { set_fast_connectable, MGMT_SETTING_SIZE },
6702 { set_bondable, MGMT_SETTING_SIZE },
6703 { set_link_security, MGMT_SETTING_SIZE },
6704 { set_ssp, MGMT_SETTING_SIZE },
6705 { set_hs, MGMT_SETTING_SIZE },
6706 { set_le, MGMT_SETTING_SIZE },
6707 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6708 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6709 { add_uuid, MGMT_ADD_UUID_SIZE },
6710 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006711 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6712 HCI_MGMT_VAR_LEN },
6713 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6714 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006715 { disconnect, MGMT_DISCONNECT_SIZE },
6716 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6717 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6718 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6719 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6720 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6721 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6722 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6723 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6724 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6725 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6726 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006727 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6728 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6729 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006730 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6731 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6732 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6733 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6734 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6735 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6736 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6737 { set_advertising, MGMT_SETTING_SIZE },
6738 { set_bredr, MGMT_SETTING_SIZE },
6739 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6740 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6741 { set_secure_conn, MGMT_SETTING_SIZE },
6742 { set_debug_keys, MGMT_SETTING_SIZE },
6743 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006744 { load_irks, MGMT_LOAD_IRKS_SIZE,
6745 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006746 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6747 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6748 { add_device, MGMT_ADD_DEVICE_SIZE },
6749 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006750 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6751 HCI_MGMT_VAR_LEN },
6752 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006753 HCI_MGMT_NO_HDEV |
6754 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006755 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006756 HCI_MGMT_UNCONFIGURED |
6757 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006758 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6759 HCI_MGMT_UNCONFIGURED },
6760 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6761 HCI_MGMT_UNCONFIGURED },
6762 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6763 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006764 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006765 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006766 HCI_MGMT_NO_HDEV |
6767 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006768 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Arman Uguray24b4f382015-03-23 15:57:12 -07006769 { add_advertising, MGMT_ADD_ADVERTISING_SIZE,
6770 HCI_MGMT_VAR_LEN },
Arman Ugurayda9293352015-03-23 15:57:13 -07006771 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006772};
6773
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006774void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006775{
Marcel Holtmannced85542015-03-14 19:27:56 -07006776 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006777
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006778 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6779 return;
6780
Marcel Holtmannf9207332015-03-14 19:27:55 -07006781 switch (hdev->dev_type) {
6782 case HCI_BREDR:
6783 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6784 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6785 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006786 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006787 } else {
6788 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6789 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006790 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006791 }
6792 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006793 case HCI_AMP:
6794 ev.type = 0x02;
6795 break;
6796 default:
6797 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006798 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006799
6800 ev.bus = hdev->bus;
6801
6802 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6803 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006804}
6805
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006806void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006807{
Marcel Holtmannced85542015-03-14 19:27:56 -07006808 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006809 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006810
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006811 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6812 return;
6813
Marcel Holtmannf9207332015-03-14 19:27:55 -07006814 switch (hdev->dev_type) {
6815 case HCI_BREDR:
6816 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006817
Marcel Holtmannf9207332015-03-14 19:27:55 -07006818 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6819 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6820 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006821 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006822 } else {
6823 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6824 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006825 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006826 }
6827 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006828 case HCI_AMP:
6829 ev.type = 0x02;
6830 break;
6831 default:
6832 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006833 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006834
6835 ev.bus = hdev->bus;
6836
6837 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6838 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006839}
6840
Andre Guedes6046dc32014-02-26 20:21:51 -03006841/* This function requires the caller holds hdev->lock */
Johan Hedberg2cf22212014-12-19 22:26:00 +02006842static void restart_le_actions(struct hci_request *req)
Andre Guedes6046dc32014-02-26 20:21:51 -03006843{
Johan Hedberg2cf22212014-12-19 22:26:00 +02006844 struct hci_dev *hdev = req->hdev;
Andre Guedes6046dc32014-02-26 20:21:51 -03006845 struct hci_conn_params *p;
6846
6847 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006848 /* Needed for AUTO_OFF case where might not "really"
6849 * have been powered off.
6850 */
6851 list_del_init(&p->action);
6852
6853 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006854 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006855 case HCI_AUTO_CONN_ALWAYS:
6856 list_add(&p->action, &hdev->pend_le_conns);
6857 break;
6858 case HCI_AUTO_CONN_REPORT:
6859 list_add(&p->action, &hdev->pend_le_reports);
6860 break;
6861 default:
6862 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006863 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006864 }
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006865
Johan Hedberg2cf22212014-12-19 22:26:00 +02006866 __hci_update_background_scan(req);
Andre Guedes6046dc32014-02-26 20:21:51 -03006867}
6868
Marcel Holtmann1904a852015-01-11 13:50:44 -08006869static void powered_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg229ab392013-03-15 17:06:53 -05006870{
6871 struct cmd_lookup match = { NULL, hdev };
6872
6873 BT_DBG("status 0x%02x", status);
6874
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006875 if (!status) {
6876 /* Register the available SMP channels (BR/EDR and LE) only
6877 * when successfully powering on the controller. This late
6878 * registration is required so that LE SMP can clearly
6879 * decide if the public address or static address is used.
6880 */
6881 smp_register(hdev);
6882 }
6883
Johan Hedberg229ab392013-03-15 17:06:53 -05006884 hci_dev_lock(hdev);
6885
6886 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6887
6888 new_settings(hdev, match.sk);
6889
6890 hci_dev_unlock(hdev);
6891
6892 if (match.sk)
6893 sock_put(match.sk);
6894}
6895
Johan Hedberg70da6242013-03-15 17:06:51 -05006896static int powered_update_hci(struct hci_dev *hdev)
6897{
Johan Hedberg890ea892013-03-15 17:06:52 -05006898 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05006899 u8 link_sec;
6900
Johan Hedberg890ea892013-03-15 17:06:52 -05006901 hci_req_init(&req, hdev);
6902
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006903 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED) &&
Johan Hedberg70da6242013-03-15 17:06:51 -05006904 !lmp_host_ssp_capable(hdev)) {
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006905 u8 mode = 0x01;
Johan Hedberg70da6242013-03-15 17:06:51 -05006906
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006907 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
Johan Hedberg70da6242013-03-15 17:06:51 -05006908
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006909 if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) {
6910 u8 support = 0x01;
6911
6912 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT,
6913 sizeof(support), &support);
6914 }
Johan Hedbergec6f99b2014-12-12 13:30:11 +02006915 }
6916
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006917 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
Johan Hedbergc73eee92013-04-19 18:35:21 +03006918 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05006919 struct hci_cp_write_le_host_supported cp;
6920
Marcel Holtmann32226e42014-07-24 20:04:16 +02006921 cp.le = 0x01;
6922 cp.simul = 0x00;
Johan Hedberg70da6242013-03-15 17:06:51 -05006923
6924 /* Check first if we already have the right
6925 * host state (host features set)
6926 */
6927 if (cp.le != lmp_host_le_capable(hdev) ||
6928 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05006929 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
6930 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05006931 }
6932
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07006933 if (lmp_le_capable(hdev)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006934 /* Make sure the controller has a good default for
6935 * advertising data. This also applies to the case
6936 * where BR/EDR was toggled during the AUTO_OFF phase.
6937 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006938 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07006939 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07006940 update_scan_rsp_data(&req);
6941 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006942
Arman Uguray24b4f382015-03-23 15:57:12 -07006943 if (hci_dev_test_flag(hdev, HCI_ADVERTISING) ||
6944 hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07006945 enable_advertising(&req);
Johan Hedberg2cf22212014-12-19 22:26:00 +02006946
6947 restart_le_actions(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03006948 }
6949
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006950 link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg70da6242013-03-15 17:06:51 -05006951 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05006952 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
6953 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05006954
6955 if (lmp_bredr_capable(hdev)) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006956 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg406ef2a2015-03-10 20:14:27 +02006957 write_fast_connectable(&req, true);
6958 else
6959 write_fast_connectable(&req, false);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02006960 __hci_update_page_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006961 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05006962 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006963 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05006964 }
6965
Johan Hedberg229ab392013-03-15 17:06:53 -05006966 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05006967}
6968
Johan Hedberg744cf192011-11-08 20:40:14 +02006969int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006970{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006971 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006972 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006973 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006974
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006975 if (!hci_dev_test_flag(hdev, HCI_MGMT))
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006976 return 0;
6977
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006978 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05006979 if (powered_update_hci(hdev) == 0)
6980 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02006981
Johan Hedberg229ab392013-03-15 17:06:53 -05006982 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
6983 &match);
6984 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006985 }
6986
Johan Hedberg229ab392013-03-15 17:06:53 -05006987 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006988
6989 /* If the power off is because of hdev unregistration let
6990 * use the appropriate INVALID_INDEX status. Otherwise use
6991 * NOT_POWERED. We cover both scenarios here since later in
6992 * mgmt_index_removed() any hci_conn callbacks will have already
6993 * been triggered, potentially causing misleading DISCONNECTED
6994 * status responses.
6995 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006996 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006997 status = MGMT_STATUS_INVALID_INDEX;
6998 else
6999 status = MGMT_STATUS_NOT_POWERED;
7000
7001 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05007002
7003 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007004 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7005 zero_cod, sizeof(zero_cod), NULL);
Johan Hedberg229ab392013-03-15 17:06:53 -05007006
7007new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02007008 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02007009
7010 if (match.sk)
7011 sock_put(match.sk);
7012
Johan Hedberg7bb895d2012-02-17 01:20:00 +02007013 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02007014}
Johan Hedberg73f22f62010-12-29 16:00:25 +02007015
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007016void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03007017{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007018 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007019 u8 status;
7020
Johan Hedberg333ae952015-03-17 13:48:47 +02007021 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007022 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07007023 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03007024
7025 if (err == -ERFKILL)
7026 status = MGMT_STATUS_RFKILLED;
7027 else
7028 status = MGMT_STATUS_FAILED;
7029
Johan Hedberga69e8372015-03-06 21:08:53 +02007030 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007031
7032 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03007033}
7034
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07007035void mgmt_discoverable_timeout(struct hci_dev *hdev)
7036{
7037 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07007038
7039 hci_dev_lock(hdev);
7040
7041 /* When discoverable timeout triggers, then just make sure
7042 * the limited discoverable flag is cleared. Even in the case
7043 * of a timeout triggered from general discoverable, it is
7044 * safe to unconditionally clear the flag.
7045 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007046 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
7047 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07007048
7049 hci_req_init(&req, hdev);
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007050 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg4b580612013-10-19 23:38:21 +03007051 u8 scan = SCAN_PAGE;
7052 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
7053 sizeof(scan), &scan);
7054 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07007055 update_class(&req);
Arman Uguray24b4f382015-03-23 15:57:12 -07007056
7057 /* Advertising instances don't use the global discoverable setting, so
7058 * only update AD if advertising was enabled using Set Advertising.
7059 */
7060 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
7061 update_adv_data(&req);
7062
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07007063 hci_req_run(&req, NULL);
7064
7065 hdev->discov_timeout = 0;
7066
Johan Hedberg9a43e252013-10-20 19:00:07 +03007067 new_settings(hdev, NULL);
7068
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07007069 hci_dev_unlock(hdev);
7070}
7071
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007072void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
7073 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007074{
Johan Hedberg86742e12011-11-07 23:13:38 +02007075 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007076
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007077 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007078
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007079 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02007080 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007081 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007082 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03007083 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007084 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007085
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007086 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007087}
Johan Hedbergf7520542011-01-20 12:34:39 +02007088
Johan Hedbergd7b25452014-05-23 13:19:53 +03007089static u8 mgmt_ltk_type(struct smp_ltk *ltk)
7090{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03007091 switch (ltk->type) {
7092 case SMP_LTK:
7093 case SMP_LTK_SLAVE:
7094 if (ltk->authenticated)
7095 return MGMT_LTK_AUTHENTICATED;
7096 return MGMT_LTK_UNAUTHENTICATED;
7097 case SMP_LTK_P256:
7098 if (ltk->authenticated)
7099 return MGMT_LTK_P256_AUTH;
7100 return MGMT_LTK_P256_UNAUTH;
7101 case SMP_LTK_P256_DEBUG:
7102 return MGMT_LTK_P256_DEBUG;
7103 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03007104
7105 return MGMT_LTK_UNAUTHENTICATED;
7106}
7107
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007108void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007109{
7110 struct mgmt_ev_new_long_term_key ev;
7111
7112 memset(&ev, 0, sizeof(ev));
7113
Marcel Holtmann5192d302014-02-19 17:11:58 -08007114 /* Devices using resolvable or non-resolvable random addresses
7115 * without providing an indentity resolving key don't require
7116 * to store long term keys. Their addresses will change the
7117 * next time around.
7118 *
7119 * Only when a remote device provides an identity address
7120 * make sure the long term key is stored. If the remote
7121 * identity is known, the long term keys are internally
7122 * mapped to the identity address. So allow static random
7123 * and public addresses here.
7124 */
Johan Hedbergba74b662014-02-19 14:57:45 +02007125 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7126 (key->bdaddr.b[5] & 0xc0) != 0xc0)
7127 ev.store_hint = 0x00;
7128 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007129 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02007130
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007131 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007132 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03007133 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007134 ev.key.enc_size = key->enc_size;
7135 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08007136 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007137
Johan Hedberg2ceba532014-06-16 19:25:16 +03007138 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007139 ev.key.master = 1;
7140
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007141 memcpy(ev.key.val, key->val, sizeof(key->val));
7142
Marcel Holtmann083368f2013-10-15 14:26:29 -07007143 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007144}
7145
Johan Hedberg95fbac82014-02-19 15:18:31 +02007146void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk)
7147{
7148 struct mgmt_ev_new_irk ev;
7149
7150 memset(&ev, 0, sizeof(ev));
7151
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08007152 /* For identity resolving keys from devices that are already
7153 * using a public address or static random address, do not
7154 * ask for storing this key. The identity resolving key really
7155 * is only mandatory for devices using resovlable random
7156 * addresses.
7157 *
7158 * Storing all identity resolving keys has the downside that
7159 * they will be also loaded on next boot of they system. More
7160 * identity resolving keys, means more time during scanning is
7161 * needed to actually resolve these addresses.
7162 */
7163 if (bacmp(&irk->rpa, BDADDR_ANY))
7164 ev.store_hint = 0x01;
7165 else
7166 ev.store_hint = 0x00;
7167
Johan Hedberg95fbac82014-02-19 15:18:31 +02007168 bacpy(&ev.rpa, &irk->rpa);
7169 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
7170 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
7171 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
7172
7173 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
7174}
7175
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007176void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
7177 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007178{
7179 struct mgmt_ev_new_csrk ev;
7180
7181 memset(&ev, 0, sizeof(ev));
7182
7183 /* Devices using resolvable or non-resolvable random addresses
7184 * without providing an indentity resolving key don't require
7185 * to store signature resolving keys. Their addresses will change
7186 * the next time around.
7187 *
7188 * Only when a remote device provides an identity address
7189 * make sure the signature resolving key is stored. So allow
7190 * static random and public addresses here.
7191 */
7192 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7193 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
7194 ev.store_hint = 0x00;
7195 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007196 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007197
7198 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
7199 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02007200 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007201 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
7202
7203 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
7204}
7205
Andre Guedesffb5a8272014-07-01 18:10:11 -03007206void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03007207 u8 bdaddr_type, u8 store_hint, u16 min_interval,
7208 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03007209{
7210 struct mgmt_ev_new_conn_param ev;
7211
Johan Hedbergc103aea2014-07-02 17:37:34 +03007212 if (!hci_is_identity_address(bdaddr, bdaddr_type))
7213 return;
7214
Andre Guedesffb5a8272014-07-01 18:10:11 -03007215 memset(&ev, 0, sizeof(ev));
7216 bacpy(&ev.addr.bdaddr, bdaddr);
7217 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03007218 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03007219 ev.min_interval = cpu_to_le16(min_interval);
7220 ev.max_interval = cpu_to_le16(max_interval);
7221 ev.latency = cpu_to_le16(latency);
7222 ev.timeout = cpu_to_le16(timeout);
7223
7224 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
7225}
7226
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007227void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
7228 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02007229{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007230 char buf[512];
7231 struct mgmt_ev_device_connected *ev = (void *) buf;
7232 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02007233
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007234 bacpy(&ev->addr.bdaddr, &conn->dst);
7235 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02007236
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02007237 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02007238
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007239 /* We must ensure that the EIR Data fields are ordered and
7240 * unique. Keep it simple for now and avoid the problem by not
7241 * adding any BR/EDR data to the LE adv.
7242 */
7243 if (conn->le_adv_data_len > 0) {
7244 memcpy(&ev->eir[eir_len],
7245 conn->le_adv_data, conn->le_adv_data_len);
7246 eir_len = conn->le_adv_data_len;
7247 } else {
7248 if (name_len > 0)
7249 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
7250 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007251
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00007252 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007253 eir_len = eir_append_data(ev->eir, eir_len,
7254 EIR_CLASS_OF_DEV,
7255 conn->dev_class, 3);
7256 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02007257
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007258 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007259
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07007260 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
7261 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02007262}
7263
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007264static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007265{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007266 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007267
Johan Hedbergf5818c22014-12-05 13:36:02 +02007268 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007269
7270 *sk = cmd->sk;
7271 sock_hold(*sk);
7272
Johan Hedberga664b5b2011-02-19 12:06:02 -03007273 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007274}
7275
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007276static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007277{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007278 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007279 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007280
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007281 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7282
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007283 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007284 mgmt_pending_remove(cmd);
7285}
7286
Johan Hedberg84c61d92014-08-01 11:13:30 +03007287bool mgmt_powering_down(struct hci_dev *hdev)
7288{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007289 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007290 struct mgmt_mode *cp;
7291
Johan Hedberg333ae952015-03-17 13:48:47 +02007292 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03007293 if (!cmd)
7294 return false;
7295
7296 cp = cmd->param;
7297 if (!cp->val)
7298 return true;
7299
7300 return false;
7301}
7302
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007303void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007304 u8 link_type, u8 addr_type, u8 reason,
7305 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007306{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007307 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007308 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007309
Johan Hedberg84c61d92014-08-01 11:13:30 +03007310 /* The connection is still in hci_conn_hash so test for 1
7311 * instead of 0 to know if this is the last one.
7312 */
7313 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7314 cancel_delayed_work(&hdev->power_off);
7315 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007316 }
7317
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007318 if (!mgmt_connected)
7319 return;
7320
Andre Guedes57eb7762013-10-30 19:01:41 -03007321 if (link_type != ACL_LINK && link_type != LE_LINK)
7322 return;
7323
Johan Hedberg744cf192011-11-08 20:40:14 +02007324 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007325
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007326 bacpy(&ev.addr.bdaddr, bdaddr);
7327 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7328 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007329
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007330 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007331
7332 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007333 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007334
Johan Hedberg124f6e32012-02-09 13:50:12 +02007335 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007336 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007337}
7338
Marcel Holtmann78929242013-10-06 23:55:47 -07007339void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7340 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007341{
Andre Guedes3655bba2013-10-30 19:01:40 -03007342 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7343 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007344 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007345
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007346 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7347 hdev);
7348
Johan Hedberg333ae952015-03-17 13:48:47 +02007349 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007350 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007351 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007352
Andre Guedes3655bba2013-10-30 19:01:40 -03007353 cp = cmd->param;
7354
7355 if (bacmp(bdaddr, &cp->addr.bdaddr))
7356 return;
7357
7358 if (cp->addr.type != bdaddr_type)
7359 return;
7360
Johan Hedbergf5818c22014-12-05 13:36:02 +02007361 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007362 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007363}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007364
Marcel Holtmann445608d2013-10-06 23:55:48 -07007365void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7366 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007367{
7368 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007369
Johan Hedberg84c61d92014-08-01 11:13:30 +03007370 /* The connection is still in hci_conn_hash so test for 1
7371 * instead of 0 to know if this is the last one.
7372 */
7373 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7374 cancel_delayed_work(&hdev->power_off);
7375 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007376 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007377
Johan Hedberg4c659c32011-11-07 23:13:39 +02007378 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007379 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007380 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007381
Marcel Holtmann445608d2013-10-06 23:55:48 -07007382 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007383}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007384
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007385void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007386{
7387 struct mgmt_ev_pin_code_request ev;
7388
Johan Hedbergd8457692012-02-17 14:24:57 +02007389 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007390 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007391 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007392
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007393 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007394}
7395
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007396void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7397 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007398{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007399 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007400
Johan Hedberg333ae952015-03-17 13:48:47 +02007401 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007402 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007403 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007404
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007405 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007406 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007407}
7408
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007409void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7410 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007411{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007412 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007413
Johan Hedberg333ae952015-03-17 13:48:47 +02007414 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007415 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007416 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007417
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007418 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007419 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007420}
Johan Hedberga5c29682011-02-19 12:05:57 -03007421
Johan Hedberg744cf192011-11-08 20:40:14 +02007422int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007423 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007424 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007425{
7426 struct mgmt_ev_user_confirm_request ev;
7427
Johan Hedberg744cf192011-11-08 20:40:14 +02007428 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007429
Johan Hedberg272d90d2012-02-09 15:26:12 +02007430 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007431 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007432 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007433 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007434
Johan Hedberg744cf192011-11-08 20:40:14 +02007435 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007436 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007437}
7438
Johan Hedberg272d90d2012-02-09 15:26:12 +02007439int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007440 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007441{
7442 struct mgmt_ev_user_passkey_request ev;
7443
7444 BT_DBG("%s", hdev->name);
7445
Johan Hedberg272d90d2012-02-09 15:26:12 +02007446 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007447 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007448
7449 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007450 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007451}
7452
Brian Gix0df4c182011-11-16 13:53:13 -08007453static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007454 u8 link_type, u8 addr_type, u8 status,
7455 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007456{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007457 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007458
Johan Hedberg333ae952015-03-17 13:48:47 +02007459 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007460 if (!cmd)
7461 return -ENOENT;
7462
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007463 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007464 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007465
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007466 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007467}
7468
Johan Hedberg744cf192011-11-08 20:40:14 +02007469int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007470 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007471{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007472 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007473 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007474}
7475
Johan Hedberg272d90d2012-02-09 15:26:12 +02007476int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007477 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007478{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007479 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007480 status,
7481 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007482}
Johan Hedberg2a611692011-02-19 12:06:00 -03007483
Brian Gix604086b2011-11-23 08:28:33 -08007484int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007485 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007486{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007487 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007488 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007489}
7490
Johan Hedberg272d90d2012-02-09 15:26:12 +02007491int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007492 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007493{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007494 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007495 status,
7496 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007497}
7498
Johan Hedberg92a25252012-09-06 18:39:26 +03007499int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7500 u8 link_type, u8 addr_type, u32 passkey,
7501 u8 entered)
7502{
7503 struct mgmt_ev_passkey_notify ev;
7504
7505 BT_DBG("%s", hdev->name);
7506
7507 bacpy(&ev.addr.bdaddr, bdaddr);
7508 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7509 ev.passkey = __cpu_to_le32(passkey);
7510 ev.entered = entered;
7511
7512 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7513}
7514
Johan Hedberge1e930f2014-09-08 17:09:49 -07007515void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007516{
7517 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007518 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007519 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007520
Johan Hedberge1e930f2014-09-08 17:09:49 -07007521 bacpy(&ev.addr.bdaddr, &conn->dst);
7522 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7523 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007524
Johan Hedberge1e930f2014-09-08 17:09:49 -07007525 cmd = find_pairing(conn);
7526
7527 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7528 cmd ? cmd->sk : NULL);
7529
Johan Hedberga511b352014-12-11 21:45:45 +02007530 if (cmd) {
7531 cmd->cmd_complete(cmd, status);
7532 mgmt_pending_remove(cmd);
7533 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007534}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007535
Marcel Holtmann464996a2013-10-15 14:26:24 -07007536void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007537{
7538 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007539 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007540
7541 if (status) {
7542 u8 mgmt_err = mgmt_status(status);
7543 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007544 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007545 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007546 }
7547
Marcel Holtmann464996a2013-10-15 14:26:24 -07007548 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007549 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007550 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007551 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007552
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007553 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007554 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007555
Johan Hedberg47990ea2012-02-22 11:58:37 +02007556 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007557 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007558
7559 if (match.sk)
7560 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007561}
7562
Johan Hedberg890ea892013-03-15 17:06:52 -05007563static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007564{
Johan Hedberg890ea892013-03-15 17:06:52 -05007565 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007566 struct hci_cp_write_eir cp;
7567
Johan Hedberg976eb202012-10-24 21:12:01 +03007568 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007569 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007570
Johan Hedbergc80da272012-02-22 15:38:48 +02007571 memset(hdev->eir, 0, sizeof(hdev->eir));
7572
Johan Hedbergcacaf522012-02-21 00:52:42 +02007573 memset(&cp, 0, sizeof(cp));
7574
Johan Hedberg890ea892013-03-15 17:06:52 -05007575 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007576}
7577
Marcel Holtmann3e248562013-10-15 14:26:25 -07007578void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007579{
7580 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007581 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007582 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007583
7584 if (status) {
7585 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007586
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007587 if (enable && hci_dev_test_and_clear_flag(hdev,
7588 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007589 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007590 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007591 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007592
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007593 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7594 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007595 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007596 }
7597
7598 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007599 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007600 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007601 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007602 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007603 changed = hci_dev_test_and_clear_flag(hdev,
7604 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007605 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007606 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007607 }
7608
7609 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7610
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007611 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007612 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007613
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007614 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007615 sock_put(match.sk);
7616
Johan Hedberg890ea892013-03-15 17:06:52 -05007617 hci_req_init(&req, hdev);
7618
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007619 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7620 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007621 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7622 sizeof(enable), &enable);
Johan Hedberg890ea892013-03-15 17:06:52 -05007623 update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007624 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007625 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007626 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007627
7628 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007629}
7630
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007631static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007632{
7633 struct cmd_lookup *match = data;
7634
Johan Hedberg90e70452012-02-23 23:09:40 +02007635 if (match->sk == NULL) {
7636 match->sk = cmd->sk;
7637 sock_hold(match->sk);
7638 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007639}
7640
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007641void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7642 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007643{
Johan Hedberg90e70452012-02-23 23:09:40 +02007644 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007645
Johan Hedberg92da6092013-03-15 17:06:55 -05007646 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7647 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7648 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007649
7650 if (!status)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007651 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7652 dev_class, 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02007653
7654 if (match.sk)
7655 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007656}
7657
Marcel Holtmann7667da32013-10-15 14:26:27 -07007658void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007659{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007660 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007661 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007662
Johan Hedberg13928972013-03-15 17:07:00 -05007663 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007664 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007665
7666 memset(&ev, 0, sizeof(ev));
7667 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007668 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007669
Johan Hedberg333ae952015-03-17 13:48:47 +02007670 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007671 if (!cmd) {
7672 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007673
Johan Hedberg13928972013-03-15 17:07:00 -05007674 /* If this is a HCI command related to powering on the
7675 * HCI dev don't send any mgmt signals.
7676 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007677 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007678 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007679 }
7680
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007681 mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7682 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007683}
Szymon Jancc35938b2011-03-22 13:12:21 +01007684
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007685void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
Johan Hedberg38da1702014-11-17 20:52:20 +02007686 u8 *rand192, u8 *hash256, u8 *rand256,
7687 u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01007688{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007689 struct mgmt_pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01007690
Johan Hedberg744cf192011-11-08 20:40:14 +02007691 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01007692
Johan Hedberg333ae952015-03-17 13:48:47 +02007693 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01007694 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07007695 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01007696
7697 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02007698 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
7699 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01007700 } else {
Johan Hedberg66f096f2015-02-02 13:23:42 +02007701 struct mgmt_rp_read_local_oob_data rp;
7702 size_t rp_size = sizeof(rp);
7703
7704 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
7705 memcpy(rp.rand192, rand192, sizeof(rp.rand192));
7706
Johan Hedberg710f11c2014-05-26 11:21:22 +03007707 if (bredr_sc_enabled(hdev) && hash256 && rand256) {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007708 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
Johan Hedberg38da1702014-11-17 20:52:20 +02007709 memcpy(rp.rand256, rand256, sizeof(rp.rand256));
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007710 } else {
Johan Hedberg66f096f2015-02-02 13:23:42 +02007711 rp_size -= sizeof(rp.hash256) + sizeof(rp.rand256);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007712 }
Johan Hedberg66f096f2015-02-02 13:23:42 +02007713
Johan Hedberg2a1afb52015-03-06 21:08:54 +02007714 mgmt_cmd_complete(cmd->sk, hdev->id,
7715 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
7716 &rp, rp_size);
Szymon Jancc35938b2011-03-22 13:12:21 +01007717 }
7718
7719 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01007720}
Johan Hedberge17acd42011-03-30 23:57:16 +03007721
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007722static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7723{
7724 int i;
7725
7726 for (i = 0; i < uuid_count; i++) {
7727 if (!memcmp(uuid, uuids[i], 16))
7728 return true;
7729 }
7730
7731 return false;
7732}
7733
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007734static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7735{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007736 u16 parsed = 0;
7737
7738 while (parsed < eir_len) {
7739 u8 field_len = eir[0];
7740 u8 uuid[16];
7741 int i;
7742
7743 if (field_len == 0)
7744 break;
7745
7746 if (eir_len - parsed < field_len + 1)
7747 break;
7748
7749 switch (eir[1]) {
7750 case EIR_UUID16_ALL:
7751 case EIR_UUID16_SOME:
7752 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007753 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007754 uuid[13] = eir[i + 3];
7755 uuid[12] = eir[i + 2];
7756 if (has_uuid(uuid, uuid_count, uuids))
7757 return true;
7758 }
7759 break;
7760 case EIR_UUID32_ALL:
7761 case EIR_UUID32_SOME:
7762 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007763 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007764 uuid[15] = eir[i + 5];
7765 uuid[14] = eir[i + 4];
7766 uuid[13] = eir[i + 3];
7767 uuid[12] = eir[i + 2];
7768 if (has_uuid(uuid, uuid_count, uuids))
7769 return true;
7770 }
7771 break;
7772 case EIR_UUID128_ALL:
7773 case EIR_UUID128_SOME:
7774 for (i = 0; i + 17 <= field_len; i += 16) {
7775 memcpy(uuid, eir + i + 2, 16);
7776 if (has_uuid(uuid, uuid_count, uuids))
7777 return true;
7778 }
7779 break;
7780 }
7781
7782 parsed += field_len + 1;
7783 eir += field_len + 1;
7784 }
7785
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007786 return false;
7787}
7788
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007789static void restart_le_scan(struct hci_dev *hdev)
7790{
7791 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007792 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007793 return;
7794
7795 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7796 hdev->discovery.scan_start +
7797 hdev->discovery.scan_duration))
7798 return;
7799
7800 queue_delayed_work(hdev->workqueue, &hdev->le_scan_restart,
7801 DISCOV_LE_RESTART_DELAY);
7802}
7803
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007804static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7805 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7806{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007807 /* If a RSSI threshold has been specified, and
7808 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7809 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7810 * is set, let it through for further processing, as we might need to
7811 * restart the scan.
7812 *
7813 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7814 * the results are also dropped.
7815 */
7816 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7817 (rssi == HCI_RSSI_INVALID ||
7818 (rssi < hdev->discovery.rssi &&
7819 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7820 return false;
7821
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007822 if (hdev->discovery.uuid_count != 0) {
7823 /* If a list of UUIDs is provided in filter, results with no
7824 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007825 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007826 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7827 hdev->discovery.uuids) &&
7828 !eir_has_uuids(scan_rsp, scan_rsp_len,
7829 hdev->discovery.uuid_count,
7830 hdev->discovery.uuids))
7831 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007832 }
7833
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007834 /* If duplicate filtering does not report RSSI changes, then restart
7835 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007836 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007837 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7838 restart_le_scan(hdev);
7839
7840 /* Validate RSSI value against the RSSI threshold once more. */
7841 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7842 rssi < hdev->discovery.rssi)
7843 return false;
7844 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007845
7846 return true;
7847}
7848
Marcel Holtmann901801b2013-10-06 23:55:51 -07007849void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007850 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7851 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007852{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007853 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007854 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007855 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007856
Johan Hedberg75ce2082014-07-02 22:42:01 +03007857 /* Don't send events for a non-kernel initiated discovery. With
7858 * LE one exception is if we have pend_le_reports > 0 in which
7859 * case we're doing passive scanning and want these events.
7860 */
7861 if (!hci_discovery_active(hdev)) {
7862 if (link_type == ACL_LINK)
7863 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007864 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007865 return;
7866 }
Andre Guedes12602d02013-04-30 15:29:40 -03007867
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007868 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007869 /* We are using service discovery */
7870 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7871 scan_rsp_len))
7872 return;
7873 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007874
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007875 /* Make sure that the buffer is big enough. The 5 extra bytes
7876 * are for the potential CoD field.
7877 */
7878 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007879 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007880
Johan Hedberg1dc06092012-01-15 21:01:23 +02007881 memset(buf, 0, sizeof(buf));
7882
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007883 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7884 * RSSI value was reported as 0 when not available. This behavior
7885 * is kept when using device discovery. This is required for full
7886 * backwards compatibility with the API.
7887 *
7888 * However when using service discovery, the value 127 will be
7889 * returned when the RSSI is not available.
7890 */
Szymon Janc91200e92015-01-22 16:57:05 +01007891 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7892 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007893 rssi = 0;
7894
Johan Hedberg841c5642014-07-07 12:45:54 +03007895 bacpy(&ev->addr.bdaddr, bdaddr);
7896 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007897 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007898 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007899
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007900 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007901 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007902 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007903
Johan Hedberg1dc06092012-01-15 21:01:23 +02007904 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
7905 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007906 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007907
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007908 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007909 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007910 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007911
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007912 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7913 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007914
Marcel Holtmann901801b2013-10-06 23:55:51 -07007915 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007916}
Johan Hedberga88a9652011-03-30 13:18:12 +03007917
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007918void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7919 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007920{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007921 struct mgmt_ev_device_found *ev;
7922 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7923 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007924
Johan Hedbergb644ba32012-01-17 21:48:47 +02007925 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007926
Johan Hedbergb644ba32012-01-17 21:48:47 +02007927 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007928
Johan Hedbergb644ba32012-01-17 21:48:47 +02007929 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007930 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007931 ev->rssi = rssi;
7932
7933 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007934 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007935
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007936 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007937
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007938 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007939}
Johan Hedberg314b2382011-04-27 10:29:57 -04007940
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007941void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007942{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007943 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007944
Andre Guedes343fb142011-11-22 17:14:19 -03007945 BT_DBG("%s discovering %u", hdev->name, discovering);
7946
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007947 memset(&ev, 0, sizeof(ev));
7948 ev.type = hdev->discovery.type;
7949 ev.discovering = discovering;
7950
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007951 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007952}
Antti Julku5e762442011-08-25 16:48:02 +03007953
Marcel Holtmann1904a852015-01-11 13:50:44 -08007954static void adv_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Marcel Holtmann5976e602013-10-06 04:08:14 -07007955{
7956 BT_DBG("%s status %u", hdev->name, status);
Marcel Holtmann5976e602013-10-06 04:08:14 -07007957}
7958
7959void mgmt_reenable_advertising(struct hci_dev *hdev)
7960{
7961 struct hci_request req;
7962
Arman Uguray24b4f382015-03-23 15:57:12 -07007963 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
7964 !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE))
Marcel Holtmann5976e602013-10-06 04:08:14 -07007965 return;
7966
7967 hci_req_init(&req, hdev);
7968 enable_advertising(&req);
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03007969 hci_req_run(&req, adv_enable_complete);
Marcel Holtmann5976e602013-10-06 04:08:14 -07007970}
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007971
7972static struct hci_mgmt_chan chan = {
7973 .channel = HCI_CHANNEL_CONTROL,
7974 .handler_count = ARRAY_SIZE(mgmt_handlers),
7975 .handlers = mgmt_handlers,
Johan Hedberg88b94ce2015-03-17 13:48:49 +02007976 .hdev_init = mgmt_init_hdev,
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007977};
7978
7979int mgmt_init(void)
7980{
7981 return hci_mgmt_chan_register(&chan);
7982}
7983
7984void mgmt_exit(void)
7985{
7986 hci_mgmt_chan_unregister(&chan);
7987}