blob: 915a2a1f0a7110cae1b0181e3a3377d65ec121de [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,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200103};
104
105static const u16 mgmt_events[] = {
106 MGMT_EV_CONTROLLER_ERROR,
107 MGMT_EV_INDEX_ADDED,
108 MGMT_EV_INDEX_REMOVED,
109 MGMT_EV_NEW_SETTINGS,
110 MGMT_EV_CLASS_OF_DEV_CHANGED,
111 MGMT_EV_LOCAL_NAME_CHANGED,
112 MGMT_EV_NEW_LINK_KEY,
113 MGMT_EV_NEW_LONG_TERM_KEY,
114 MGMT_EV_DEVICE_CONNECTED,
115 MGMT_EV_DEVICE_DISCONNECTED,
116 MGMT_EV_CONNECT_FAILED,
117 MGMT_EV_PIN_CODE_REQUEST,
118 MGMT_EV_USER_CONFIRM_REQUEST,
119 MGMT_EV_USER_PASSKEY_REQUEST,
120 MGMT_EV_AUTH_FAILED,
121 MGMT_EV_DEVICE_FOUND,
122 MGMT_EV_DISCOVERING,
123 MGMT_EV_DEVICE_BLOCKED,
124 MGMT_EV_DEVICE_UNBLOCKED,
125 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300126 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800127 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700128 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200129 MGMT_EV_DEVICE_ADDED,
130 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300131 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200132 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd3896b2014-07-02 21:30:55 +0200133 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200134 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700135 MGMT_EV_EXT_INDEX_ADDED,
136 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700137 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200138};
139
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800140#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200141
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200142#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
143 "\x00\x00\x00\x00\x00\x00\x00\x00"
144
Johan Hedbergca69b792011-11-11 18:10:00 +0200145/* HCI to MGMT error code conversion table */
146static u8 mgmt_status_table[] = {
147 MGMT_STATUS_SUCCESS,
148 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
149 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
150 MGMT_STATUS_FAILED, /* Hardware Failure */
151 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
152 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200153 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200154 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
155 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
156 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
157 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
158 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
159 MGMT_STATUS_BUSY, /* Command Disallowed */
160 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
161 MGMT_STATUS_REJECTED, /* Rejected Security */
162 MGMT_STATUS_REJECTED, /* Rejected Personal */
163 MGMT_STATUS_TIMEOUT, /* Host Timeout */
164 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
166 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
167 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
168 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
169 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
170 MGMT_STATUS_BUSY, /* Repeated Attempts */
171 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
172 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
173 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
174 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
175 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
176 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
177 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
178 MGMT_STATUS_FAILED, /* Unspecified Error */
179 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
180 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
181 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
182 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
183 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
184 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
185 MGMT_STATUS_FAILED, /* Unit Link Key Used */
186 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
187 MGMT_STATUS_TIMEOUT, /* Instant Passed */
188 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
189 MGMT_STATUS_FAILED, /* Transaction Collision */
190 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
191 MGMT_STATUS_REJECTED, /* QoS Rejected */
192 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
193 MGMT_STATUS_REJECTED, /* Insufficient Security */
194 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
195 MGMT_STATUS_BUSY, /* Role Switch Pending */
196 MGMT_STATUS_FAILED, /* Slot Violation */
197 MGMT_STATUS_FAILED, /* Role Switch Failed */
198 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
199 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
200 MGMT_STATUS_BUSY, /* Host Busy Pairing */
201 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
202 MGMT_STATUS_BUSY, /* Controller Busy */
203 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
204 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
205 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
206 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
207 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
208};
209
210static u8 mgmt_status(u8 hci_status)
211{
212 if (hci_status < ARRAY_SIZE(mgmt_status_table))
213 return mgmt_status_table[hci_status];
214
215 return MGMT_STATUS_FAILED;
216}
217
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700218static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
219 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700220{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700221 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
222 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700223}
224
Marcel Holtmann72000df2015-03-16 16:11:21 -0700225static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
226 u16 len, int flag, struct sock *skip_sk)
227{
228 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
229 flag, skip_sk);
230}
231
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700232static int mgmt_generic_event(u16 event, struct hci_dev *hdev, void *data,
233 u16 len, struct sock *skip_sk)
234{
235 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
236 HCI_MGMT_GENERIC_EVENTS, skip_sk);
237}
238
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200239static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
240 struct sock *skip_sk)
241{
242 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700243 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200244}
245
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300246static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
247 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200248{
249 struct mgmt_rp_read_version rp;
250
251 BT_DBG("sock %p", sk);
252
253 rp.version = MGMT_VERSION;
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700254 rp.revision = cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200255
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200256 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
257 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200258}
259
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300260static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
261 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200262{
263 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200264 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
265 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200266 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200267 size_t rp_size;
268 int i, err;
269
270 BT_DBG("sock %p", sk);
271
272 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
273
274 rp = kmalloc(rp_size, GFP_KERNEL);
275 if (!rp)
276 return -ENOMEM;
277
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700278 rp->num_commands = cpu_to_le16(num_commands);
279 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200280
281 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
282 put_unaligned_le16(mgmt_commands[i], opcode);
283
284 for (i = 0; i < num_events; i++, opcode++)
285 put_unaligned_le16(mgmt_events[i], opcode);
286
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200287 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
288 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200289 kfree(rp);
290
291 return err;
292}
293
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300294static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
295 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200296{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200297 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200298 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200299 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200300 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300301 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200302
303 BT_DBG("sock %p", sk);
304
305 read_lock(&hci_dev_list_lock);
306
307 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300308 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200309 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700310 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700311 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200312 }
313
Johan Hedberga38528f2011-01-22 06:46:43 +0200314 rp_len = sizeof(*rp) + (2 * count);
315 rp = kmalloc(rp_len, GFP_ATOMIC);
316 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100317 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100319 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200320
Johan Hedberg476e44c2012-10-19 20:10:46 +0300321 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200322 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700323 if (hci_dev_test_flag(d, HCI_SETUP) ||
324 hci_dev_test_flag(d, HCI_CONFIG) ||
325 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200326 continue;
327
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200328 /* Devices marked as raw-only are neither configured
329 * nor unconfigured controllers.
330 */
331 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700332 continue;
333
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200334 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700335 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700336 rp->index[count++] = cpu_to_le16(d->id);
337 BT_DBG("Added hci%u", d->id);
338 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200339 }
340
Johan Hedberg476e44c2012-10-19 20:10:46 +0300341 rp->num_controllers = cpu_to_le16(count);
342 rp_len = sizeof(*rp) + (2 * count);
343
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200344 read_unlock(&hci_dev_list_lock);
345
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200346 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
347 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348
Johan Hedberga38528f2011-01-22 06:46:43 +0200349 kfree(rp);
350
351 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200352}
353
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200354static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
355 void *data, u16 data_len)
356{
357 struct mgmt_rp_read_unconf_index_list *rp;
358 struct hci_dev *d;
359 size_t rp_len;
360 u16 count;
361 int err;
362
363 BT_DBG("sock %p", sk);
364
365 read_lock(&hci_dev_list_lock);
366
367 count = 0;
368 list_for_each_entry(d, &hci_dev_list, list) {
369 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700370 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200371 count++;
372 }
373
374 rp_len = sizeof(*rp) + (2 * count);
375 rp = kmalloc(rp_len, GFP_ATOMIC);
376 if (!rp) {
377 read_unlock(&hci_dev_list_lock);
378 return -ENOMEM;
379 }
380
381 count = 0;
382 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700383 if (hci_dev_test_flag(d, HCI_SETUP) ||
384 hci_dev_test_flag(d, HCI_CONFIG) ||
385 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200386 continue;
387
388 /* Devices marked as raw-only are neither configured
389 * nor unconfigured controllers.
390 */
391 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
392 continue;
393
394 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700395 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200396 rp->index[count++] = cpu_to_le16(d->id);
397 BT_DBG("Added hci%u", d->id);
398 }
399 }
400
401 rp->num_controllers = cpu_to_le16(count);
402 rp_len = sizeof(*rp) + (2 * count);
403
404 read_unlock(&hci_dev_list_lock);
405
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200406 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
407 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200408
409 kfree(rp);
410
411 return err;
412}
413
Marcel Holtmann96f14742015-03-14 19:27:57 -0700414static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
415 void *data, u16 data_len)
416{
417 struct mgmt_rp_read_ext_index_list *rp;
418 struct hci_dev *d;
419 size_t rp_len;
420 u16 count;
421 int err;
422
423 BT_DBG("sock %p", sk);
424
425 read_lock(&hci_dev_list_lock);
426
427 count = 0;
428 list_for_each_entry(d, &hci_dev_list, list) {
429 if (d->dev_type == HCI_BREDR || d->dev_type == HCI_AMP)
430 count++;
431 }
432
433 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
434 rp = kmalloc(rp_len, GFP_ATOMIC);
435 if (!rp) {
436 read_unlock(&hci_dev_list_lock);
437 return -ENOMEM;
438 }
439
440 count = 0;
441 list_for_each_entry(d, &hci_dev_list, list) {
442 if (hci_dev_test_flag(d, HCI_SETUP) ||
443 hci_dev_test_flag(d, HCI_CONFIG) ||
444 hci_dev_test_flag(d, HCI_USER_CHANNEL))
445 continue;
446
447 /* Devices marked as raw-only are neither configured
448 * nor unconfigured controllers.
449 */
450 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
451 continue;
452
453 if (d->dev_type == HCI_BREDR) {
454 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
455 rp->entry[count].type = 0x01;
456 else
457 rp->entry[count].type = 0x00;
458 } else if (d->dev_type == HCI_AMP) {
459 rp->entry[count].type = 0x02;
460 } else {
461 continue;
462 }
463
464 rp->entry[count].bus = d->bus;
465 rp->entry[count++].index = cpu_to_le16(d->id);
466 BT_DBG("Added hci%u", d->id);
467 }
468
469 rp->num_controllers = cpu_to_le16(count);
470 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
471
472 read_unlock(&hci_dev_list_lock);
473
474 /* If this command is called at least once, then all the
475 * default index and unconfigured index events are disabled
476 * and from now on only extended index events are used.
477 */
478 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
479 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
480 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
481
482 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
483 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
484
485 kfree(rp);
486
487 return err;
488}
489
Marcel Holtmanndbece372014-07-04 18:11:55 +0200490static bool is_configured(struct hci_dev *hdev)
491{
492 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700493 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200494 return false;
495
496 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
497 !bacmp(&hdev->public_addr, BDADDR_ANY))
498 return false;
499
500 return true;
501}
502
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200503static __le32 get_missing_options(struct hci_dev *hdev)
504{
505 u32 options = 0;
506
Marcel Holtmanndbece372014-07-04 18:11:55 +0200507 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700508 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200509 options |= MGMT_OPTION_EXTERNAL_CONFIG;
510
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200511 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
512 !bacmp(&hdev->public_addr, BDADDR_ANY))
513 options |= MGMT_OPTION_PUBLIC_ADDRESS;
514
515 return cpu_to_le32(options);
516}
517
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200518static int new_options(struct hci_dev *hdev, struct sock *skip)
519{
520 __le32 options = get_missing_options(hdev);
521
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700522 return mgmt_generic_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
523 sizeof(options), skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200524}
525
Marcel Holtmanndbece372014-07-04 18:11:55 +0200526static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
527{
528 __le32 options = get_missing_options(hdev);
529
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200530 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
531 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200532}
533
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200534static int read_config_info(struct sock *sk, struct hci_dev *hdev,
535 void *data, u16 data_len)
536{
537 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200538 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200539
540 BT_DBG("sock %p %s", sk, hdev->name);
541
542 hci_dev_lock(hdev);
543
544 memset(&rp, 0, sizeof(rp));
545 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200546
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200547 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
548 options |= MGMT_OPTION_EXTERNAL_CONFIG;
549
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200550 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200551 options |= MGMT_OPTION_PUBLIC_ADDRESS;
552
553 rp.supported_options = cpu_to_le32(options);
554 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200555
556 hci_dev_unlock(hdev);
557
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200558 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
559 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200560}
561
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200562static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200563{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200564 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200565
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200566 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300567 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800568 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300569 settings |= MGMT_SETTING_CONNECTABLE;
570 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200571
Andre Guedesed3fa312012-07-24 15:03:46 -0300572 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500573 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
574 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200575 settings |= MGMT_SETTING_BREDR;
576 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700577
578 if (lmp_ssp_capable(hdev)) {
579 settings |= MGMT_SETTING_SSP;
580 settings |= MGMT_SETTING_HS;
581 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800582
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800583 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800584 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700585 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100586
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300587 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200588 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300589 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300590 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200591 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800592 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300593 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200594
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200595 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
596 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200597 settings |= MGMT_SETTING_CONFIGURATION;
598
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200599 return settings;
600}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200601
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200602static u32 get_current_settings(struct hci_dev *hdev)
603{
604 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200605
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200606 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100607 settings |= MGMT_SETTING_POWERED;
608
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700609 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200610 settings |= MGMT_SETTING_CONNECTABLE;
611
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700612 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500613 settings |= MGMT_SETTING_FAST_CONNECTABLE;
614
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700615 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200616 settings |= MGMT_SETTING_DISCOVERABLE;
617
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700618 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300619 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200620
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700621 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200622 settings |= MGMT_SETTING_BREDR;
623
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700624 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200625 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200626
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700627 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200628 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200629
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700630 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200631 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200632
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700633 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200634 settings |= MGMT_SETTING_HS;
635
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700636 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300637 settings |= MGMT_SETTING_ADVERTISING;
638
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700639 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800640 settings |= MGMT_SETTING_SECURE_CONN;
641
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700642 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800643 settings |= MGMT_SETTING_DEBUG_KEYS;
644
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700645 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200646 settings |= MGMT_SETTING_PRIVACY;
647
Marcel Holtmann93690c22015-03-06 10:11:21 -0800648 /* The current setting for static address has two purposes. The
649 * first is to indicate if the static address will be used and
650 * the second is to indicate if it is actually set.
651 *
652 * This means if the static address is not configured, this flag
653 * will never bet set. If the address is configured, then if the
654 * address is actually used decides if the flag is set or not.
655 *
656 * For single mode LE only controllers and dual-mode controllers
657 * with BR/EDR disabled, the existence of the static address will
658 * be evaluated.
659 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700660 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700661 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800662 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
663 if (bacmp(&hdev->static_addr, BDADDR_ANY))
664 settings |= MGMT_SETTING_STATIC_ADDRESS;
665 }
666
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200667 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200668}
669
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300670#define PNP_INFO_SVCLASS_ID 0x1200
671
Johan Hedberg213202e2013-01-27 00:31:33 +0200672static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
673{
674 u8 *ptr = data, *uuids_start = NULL;
675 struct bt_uuid *uuid;
676
677 if (len < 4)
678 return ptr;
679
680 list_for_each_entry(uuid, &hdev->uuids, list) {
681 u16 uuid16;
682
683 if (uuid->size != 16)
684 continue;
685
686 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
687 if (uuid16 < 0x1100)
688 continue;
689
690 if (uuid16 == PNP_INFO_SVCLASS_ID)
691 continue;
692
693 if (!uuids_start) {
694 uuids_start = ptr;
695 uuids_start[0] = 1;
696 uuids_start[1] = EIR_UUID16_ALL;
697 ptr += 2;
698 }
699
700 /* Stop if not enough space to put next UUID */
701 if ((ptr - data) + sizeof(u16) > len) {
702 uuids_start[1] = EIR_UUID16_SOME;
703 break;
704 }
705
706 *ptr++ = (uuid16 & 0x00ff);
707 *ptr++ = (uuid16 & 0xff00) >> 8;
708 uuids_start[0] += sizeof(uuid16);
709 }
710
711 return ptr;
712}
713
Johan Hedbergcdf19632013-01-27 00:31:34 +0200714static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
715{
716 u8 *ptr = data, *uuids_start = NULL;
717 struct bt_uuid *uuid;
718
719 if (len < 6)
720 return ptr;
721
722 list_for_each_entry(uuid, &hdev->uuids, list) {
723 if (uuid->size != 32)
724 continue;
725
726 if (!uuids_start) {
727 uuids_start = ptr;
728 uuids_start[0] = 1;
729 uuids_start[1] = EIR_UUID32_ALL;
730 ptr += 2;
731 }
732
733 /* Stop if not enough space to put next UUID */
734 if ((ptr - data) + sizeof(u32) > len) {
735 uuids_start[1] = EIR_UUID32_SOME;
736 break;
737 }
738
739 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
740 ptr += sizeof(u32);
741 uuids_start[0] += sizeof(u32);
742 }
743
744 return ptr;
745}
746
Johan Hedbergc00d5752013-01-27 00:31:35 +0200747static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
748{
749 u8 *ptr = data, *uuids_start = NULL;
750 struct bt_uuid *uuid;
751
752 if (len < 18)
753 return ptr;
754
755 list_for_each_entry(uuid, &hdev->uuids, list) {
756 if (uuid->size != 128)
757 continue;
758
759 if (!uuids_start) {
760 uuids_start = ptr;
761 uuids_start[0] = 1;
762 uuids_start[1] = EIR_UUID128_ALL;
763 ptr += 2;
764 }
765
766 /* Stop if not enough space to put next UUID */
767 if ((ptr - data) + 16 > len) {
768 uuids_start[1] = EIR_UUID128_SOME;
769 break;
770 }
771
772 memcpy(ptr, uuid->uuid, 16);
773 ptr += 16;
774 uuids_start[0] += 16;
775 }
776
777 return ptr;
778}
779
Johan Hedberg333ae952015-03-17 13:48:47 +0200780static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
781{
782 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
783}
784
Johan Hedberg333ae952015-03-17 13:48:47 +0200785static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
786 struct hci_dev *hdev,
787 const void *data)
788{
789 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
790}
791
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700792static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
793{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700794 u8 ad_len = 0;
795 size_t name_len;
796
797 name_len = strlen(hdev->dev_name);
798 if (name_len > 0) {
799 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
800
801 if (name_len > max_len) {
802 name_len = max_len;
803 ptr[1] = EIR_NAME_SHORT;
804 } else
805 ptr[1] = EIR_NAME_COMPLETE;
806
807 ptr[0] = name_len + 1;
808
809 memcpy(ptr + 2, hdev->dev_name, name_len);
810
811 ad_len += (name_len + 2);
812 ptr += (name_len + 2);
813 }
814
815 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700816}
817
818static void update_scan_rsp_data(struct hci_request *req)
819{
820 struct hci_dev *hdev = req->hdev;
821 struct hci_cp_le_set_scan_rsp_data cp;
822 u8 len;
823
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700824 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700825 return;
826
827 memset(&cp, 0, sizeof(cp));
828
829 len = create_scan_rsp_data(hdev, cp.data);
830
Johan Hedbergeb438b52013-10-16 15:31:07 +0300831 if (hdev->scan_rsp_data_len == len &&
832 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700833 return;
834
Johan Hedbergeb438b52013-10-16 15:31:07 +0300835 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
836 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700837
838 cp.length = len;
839
840 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
841}
842
Johan Hedberg9a43e252013-10-20 19:00:07 +0300843static u8 get_adv_discov_flags(struct hci_dev *hdev)
844{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200845 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300846
847 /* If there's a pending mgmt command the flags will not yet have
848 * their final values, so check for this first.
849 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200850 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300851 if (cmd) {
852 struct mgmt_mode *cp = cmd->param;
853 if (cp->val == 0x01)
854 return LE_AD_GENERAL;
855 else if (cp->val == 0x02)
856 return LE_AD_LIMITED;
857 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700858 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300859 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700860 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300861 return LE_AD_GENERAL;
862 }
863
864 return 0;
865}
866
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700867static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700868{
869 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700870
Johan Hedberg9a43e252013-10-20 19:00:07 +0300871 flags |= get_adv_discov_flags(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700872
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700873 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700874 flags |= LE_AD_NO_BREDR;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700875
876 if (flags) {
877 BT_DBG("adv flags 0x%02x", flags);
878
879 ptr[0] = 2;
880 ptr[1] = EIR_FLAGS;
881 ptr[2] = flags;
882
883 ad_len += 3;
884 ptr += 3;
885 }
886
887 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
888 ptr[0] = 2;
889 ptr[1] = EIR_TX_POWER;
890 ptr[2] = (u8) hdev->adv_tx_power;
891
892 ad_len += 3;
893 ptr += 3;
894 }
895
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700896 return ad_len;
897}
898
Marcel Holtmann5947f4b2013-10-16 00:16:50 -0700899static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700900{
901 struct hci_dev *hdev = req->hdev;
902 struct hci_cp_le_set_adv_data cp;
903 u8 len;
904
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700905 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700906 return;
907
908 memset(&cp, 0, sizeof(cp));
909
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700910 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700911
912 if (hdev->adv_data_len == len &&
913 memcmp(cp.data, hdev->adv_data, len) == 0)
914 return;
915
916 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
917 hdev->adv_data_len = len;
918
919 cp.length = len;
920
921 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
922}
923
Johan Hedbergbc6d2d02014-07-10 12:09:08 +0300924int mgmt_update_adv_data(struct hci_dev *hdev)
925{
926 struct hci_request req;
927
928 hci_req_init(&req, hdev);
929 update_adv_data(&req);
930
931 return hci_req_run(&req, NULL);
932}
933
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300934static void create_eir(struct hci_dev *hdev, u8 *data)
935{
936 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300937 size_t name_len;
938
939 name_len = strlen(hdev->dev_name);
940
941 if (name_len > 0) {
942 /* EIR Data type */
943 if (name_len > 48) {
944 name_len = 48;
945 ptr[1] = EIR_NAME_SHORT;
946 } else
947 ptr[1] = EIR_NAME_COMPLETE;
948
949 /* EIR Data length */
950 ptr[0] = name_len + 1;
951
952 memcpy(ptr + 2, hdev->dev_name, name_len);
953
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300954 ptr += (name_len + 2);
955 }
956
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100957 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700958 ptr[0] = 2;
959 ptr[1] = EIR_TX_POWER;
960 ptr[2] = (u8) hdev->inq_tx_power;
961
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700962 ptr += 3;
963 }
964
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700965 if (hdev->devid_source > 0) {
966 ptr[0] = 9;
967 ptr[1] = EIR_DEVICE_ID;
968
969 put_unaligned_le16(hdev->devid_source, ptr + 2);
970 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
971 put_unaligned_le16(hdev->devid_product, ptr + 6);
972 put_unaligned_le16(hdev->devid_version, ptr + 8);
973
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700974 ptr += 10;
975 }
976
Johan Hedberg213202e2013-01-27 00:31:33 +0200977 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200978 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200979 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300980}
981
Johan Hedberg890ea892013-03-15 17:06:52 -0500982static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300983{
Johan Hedberg890ea892013-03-15 17:06:52 -0500984 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300985 struct hci_cp_write_eir cp;
986
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200987 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500988 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200989
Johan Hedberg976eb202012-10-24 21:12:01 +0300990 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500991 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300992
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700993 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg890ea892013-03-15 17:06:52 -0500994 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300995
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700996 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -0500997 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300998
999 memset(&cp, 0, sizeof(cp));
1000
1001 create_eir(hdev, cp.data);
1002
1003 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -05001004 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001005
1006 memcpy(hdev->eir, cp.data, sizeof(cp.data));
1007
Johan Hedberg890ea892013-03-15 17:06:52 -05001008 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001009}
1010
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001011static u8 get_service_classes(struct hci_dev *hdev)
1012{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -03001013 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001014 u8 val = 0;
1015
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -03001016 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001017 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001018
1019 return val;
1020}
1021
Johan Hedberg890ea892013-03-15 17:06:52 -05001022static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001023{
Johan Hedberg890ea892013-03-15 17:06:52 -05001024 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001025 u8 cod[3];
1026
1027 BT_DBG("%s", hdev->name);
1028
Johan Hedberg504c8dc2012-02-23 13:30:41 +02001029 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001030 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +02001031
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001032 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedbergf87ea1d2013-10-19 23:38:17 +03001033 return;
1034
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001035 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -05001036 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001037
1038 cod[0] = hdev->minor_class;
1039 cod[1] = hdev->major_class;
1040 cod[2] = get_service_classes(hdev);
1041
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001042 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Marcel Holtmann6acd7db2013-10-15 06:33:53 -07001043 cod[1] |= 0x20;
1044
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001045 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -05001046 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001047
Johan Hedberg890ea892013-03-15 17:06:52 -05001048 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001049}
1050
Johan Hedberga4858cb2014-02-25 19:56:31 +02001051static bool get_connectable(struct hci_dev *hdev)
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001052{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001053 struct mgmt_pending_cmd *cmd;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001054
1055 /* If there's a pending mgmt command the flag will not yet have
1056 * it's final value, so check for this first.
1057 */
Johan Hedberg333ae952015-03-17 13:48:47 +02001058 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001059 if (cmd) {
1060 struct mgmt_mode *cp = cmd->param;
Johan Hedberga4858cb2014-02-25 19:56:31 +02001061 return cp->val;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001062 }
1063
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001064 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001065}
1066
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001067static void disable_advertising(struct hci_request *req)
1068{
1069 u8 enable = 0x00;
1070
1071 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1072}
1073
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001074static void enable_advertising(struct hci_request *req)
1075{
1076 struct hci_dev *hdev = req->hdev;
1077 struct hci_cp_le_set_adv_param cp;
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001078 u8 own_addr_type, enable = 0x01;
Johan Hedberga4858cb2014-02-25 19:56:31 +02001079 bool connectable;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001080
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001081 if (hci_conn_num(hdev, LE_LINK) > 0)
1082 return;
1083
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001084 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001085 disable_advertising(req);
1086
Johan Hedberg5ce194c2014-07-08 15:07:49 +03001087 /* Clear the HCI_LE_ADV bit temporarily so that the
Johan Hedberg8d972502014-02-28 12:54:14 +02001088 * hci_update_random_address knows that it's safe to go ahead
1089 * and write a new random address. The flag will be set back on
1090 * as soon as the SET_ADV_ENABLE HCI command completes.
1091 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001092 hci_dev_clear_flag(hdev, HCI_LE_ADV);
Johan Hedberg8d972502014-02-28 12:54:14 +02001093
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001094 if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07001095 connectable = true;
1096 else
1097 connectable = get_connectable(hdev);
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001098
Johan Hedberga4858cb2014-02-25 19:56:31 +02001099 /* Set require_privacy to true only when non-connectable
1100 * advertising is used. In that case it is fine to use a
1101 * non-resolvable private address.
1102 */
1103 if (hci_update_random_address(req, !connectable, &own_addr_type) < 0)
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001104 return;
1105
Marcel Holtmann41c90c12014-02-23 20:25:55 -08001106 memset(&cp, 0, sizeof(cp));
Georg Lukas628531c2014-07-26 13:59:57 +02001107 cp.min_interval = cpu_to_le16(hdev->le_adv_min_interval);
1108 cp.max_interval = cpu_to_le16(hdev->le_adv_max_interval);
Johan Hedberga4858cb2014-02-25 19:56:31 +02001109 cp.type = connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001110 cp.own_address_type = own_addr_type;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001111 cp.channel_map = hdev->le_adv_channel_map;
1112
1113 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1114
1115 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1116}
1117
Johan Hedberg7d785252011-12-15 00:47:39 +02001118static void service_cache_off(struct work_struct *work)
1119{
1120 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001121 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -05001122 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +02001123
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001124 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +02001125 return;
1126
Johan Hedberg890ea892013-03-15 17:06:52 -05001127 hci_req_init(&req, hdev);
1128
Johan Hedberg7d785252011-12-15 00:47:39 +02001129 hci_dev_lock(hdev);
1130
Johan Hedberg890ea892013-03-15 17:06:52 -05001131 update_eir(&req);
1132 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001133
1134 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001135
1136 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +02001137}
1138
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001139static void rpa_expired(struct work_struct *work)
1140{
1141 struct hci_dev *hdev = container_of(work, struct hci_dev,
1142 rpa_expired.work);
1143 struct hci_request req;
1144
1145 BT_DBG("");
1146
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001147 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001148
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001149 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001150 return;
1151
1152 /* The generation of a new RPA and programming it into the
1153 * controller happens in the enable_advertising() function.
1154 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001155 hci_req_init(&req, hdev);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001156 enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001157 hci_req_run(&req, NULL);
1158}
1159
Johan Hedberg6a919082012-02-28 06:17:26 +02001160static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +02001161{
Marcel Holtmann238be782015-03-13 02:11:06 -07001162 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +02001163 return;
1164
Johan Hedberg4f87da82012-03-02 19:55:56 +02001165 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001166 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +02001167
Johan Hedberg4f87da82012-03-02 19:55:56 +02001168 /* Non-mgmt controlled devices get this bit set
1169 * implicitly so that pairing works for them, however
1170 * for mgmt we require user-space to explicitly enable
1171 * it
1172 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001173 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +02001174}
1175
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001176static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001177 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001178{
1179 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001180
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001181 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001182
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001183 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001184
Johan Hedberg03811012010-12-08 00:21:06 +02001185 memset(&rp, 0, sizeof(rp));
1186
Johan Hedberg03811012010-12-08 00:21:06 +02001187 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001188
1189 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001190 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001191
1192 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1193 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1194
1195 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +02001196
1197 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001198 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +02001199
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001200 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001201
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001202 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1203 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +02001204}
1205
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001206static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001207{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001208 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001209
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001210 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1211 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001212}
1213
Marcel Holtmann1904a852015-01-11 13:50:44 -08001214static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001215{
1216 BT_DBG("%s status 0x%02x", hdev->name, status);
1217
Johan Hedberga3172b72014-02-28 09:33:44 +02001218 if (hci_conn_count(hdev) == 0) {
1219 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001220 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001221 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001222}
1223
Johan Hedberg23a48092014-07-08 16:05:06 +03001224static bool hci_stop_discovery(struct hci_request *req)
Johan Hedberg21a60d32014-06-10 14:05:58 +03001225{
1226 struct hci_dev *hdev = req->hdev;
1227 struct hci_cp_remote_name_req_cancel cp;
1228 struct inquiry_entry *e;
1229
1230 switch (hdev->discovery.state) {
1231 case DISCOVERY_FINDING:
Jakub Pawlowski07d23342015-03-17 09:04:14 -07001232 if (test_bit(HCI_INQUIRY, &hdev->flags))
Johan Hedberg21a60d32014-06-10 14:05:58 +03001233 hci_req_add(req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
Jakub Pawlowski07d23342015-03-17 09:04:14 -07001234
1235 if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
Johan Hedberg21a60d32014-06-10 14:05:58 +03001236 cancel_delayed_work(&hdev->le_scan_disable);
1237 hci_req_add_le_scan_disable(req);
1238 }
1239
Johan Hedberg23a48092014-07-08 16:05:06 +03001240 return true;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001241
1242 case DISCOVERY_RESOLVING:
1243 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
1244 NAME_PENDING);
1245 if (!e)
Johan Hedberg23a48092014-07-08 16:05:06 +03001246 break;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001247
1248 bacpy(&cp.bdaddr, &e->data.bdaddr);
1249 hci_req_add(req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
1250 &cp);
1251
Johan Hedberg23a48092014-07-08 16:05:06 +03001252 return true;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001253
1254 default:
1255 /* Passive scanning */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001256 if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
Johan Hedberg21a60d32014-06-10 14:05:58 +03001257 hci_req_add_le_scan_disable(req);
Johan Hedberg23a48092014-07-08 16:05:06 +03001258 return true;
1259 }
1260
Johan Hedberg21a60d32014-06-10 14:05:58 +03001261 break;
1262 }
Johan Hedberg23a48092014-07-08 16:05:06 +03001263
1264 return false;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001265}
1266
Johan Hedberg8b064a32014-02-24 14:52:22 +02001267static int clean_up_hci_state(struct hci_dev *hdev)
1268{
1269 struct hci_request req;
1270 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001271 bool discov_stopped;
1272 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001273
1274 hci_req_init(&req, hdev);
1275
1276 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1277 test_bit(HCI_PSCAN, &hdev->flags)) {
1278 u8 scan = 0x00;
1279 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1280 }
1281
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001282 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedberg8b064a32014-02-24 14:52:22 +02001283 disable_advertising(&req);
1284
Johan Hedberg23a48092014-07-08 16:05:06 +03001285 discov_stopped = hci_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001286
1287 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
1288 struct hci_cp_disconnect dc;
Johan Hedbergc9910d02014-02-27 14:35:12 +02001289 struct hci_cp_reject_conn_req rej;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001290
Johan Hedbergc9910d02014-02-27 14:35:12 +02001291 switch (conn->state) {
1292 case BT_CONNECTED:
1293 case BT_CONFIG:
1294 dc.handle = cpu_to_le16(conn->handle);
1295 dc.reason = 0x15; /* Terminated due to Power Off */
1296 hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1297 break;
1298 case BT_CONNECT:
1299 if (conn->type == LE_LINK)
1300 hci_req_add(&req, HCI_OP_LE_CREATE_CONN_CANCEL,
1301 0, NULL);
1302 else if (conn->type == ACL_LINK)
1303 hci_req_add(&req, HCI_OP_CREATE_CONN_CANCEL,
1304 6, &conn->dst);
1305 break;
1306 case BT_CONNECT2:
1307 bacpy(&rej.bdaddr, &conn->dst);
1308 rej.reason = 0x15; /* Terminated due to Power Off */
1309 if (conn->type == ACL_LINK)
1310 hci_req_add(&req, HCI_OP_REJECT_CONN_REQ,
1311 sizeof(rej), &rej);
1312 else if (conn->type == SCO_LINK)
1313 hci_req_add(&req, HCI_OP_REJECT_SYNC_CONN_REQ,
1314 sizeof(rej), &rej);
1315 break;
1316 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001317 }
1318
Johan Hedberg23a48092014-07-08 16:05:06 +03001319 err = hci_req_run(&req, clean_up_hci_complete);
1320 if (!err && discov_stopped)
1321 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1322
1323 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001324}
1325
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001326static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001327 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001328{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001329 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001330 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001331 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001332
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001333 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001334
Johan Hedberga7e80f22013-01-09 16:05:19 +02001335 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001336 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1337 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001338
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001339 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001340
Johan Hedberg333ae952015-03-17 13:48:47 +02001341 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001342 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1343 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001344 goto failed;
1345 }
1346
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001347 if (hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001348 cancel_delayed_work(&hdev->power_off);
1349
1350 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +02001351 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
1352 data, len);
1353 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001354 goto failed;
1355 }
1356 }
1357
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001358 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001359 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001360 goto failed;
1361 }
1362
Johan Hedberg03811012010-12-08 00:21:06 +02001363 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1364 if (!cmd) {
1365 err = -ENOMEM;
1366 goto failed;
1367 }
1368
Johan Hedberg8b064a32014-02-24 14:52:22 +02001369 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001370 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001371 err = 0;
1372 } else {
1373 /* Disconnect connections, stop scans, etc */
1374 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001375 if (!err)
1376 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1377 HCI_POWER_OFF_TIMEOUT);
Johan Hedberg03811012010-12-08 00:21:06 +02001378
Johan Hedberg8b064a32014-02-24 14:52:22 +02001379 /* ENODATA means there were no HCI commands queued */
1380 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001381 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001382 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1383 err = 0;
1384 }
1385 }
Johan Hedberg03811012010-12-08 00:21:06 +02001386
1387failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001388 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001389 return err;
1390}
1391
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001392static int new_settings(struct hci_dev *hdev, struct sock *skip)
1393{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001394 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001395
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001396 return mgmt_generic_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1397 sizeof(ev), skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001398}
1399
Johan Hedberg91a668b2014-07-09 13:28:26 +03001400int mgmt_new_settings(struct hci_dev *hdev)
1401{
1402 return new_settings(hdev, NULL);
1403}
1404
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001405struct cmd_lookup {
1406 struct sock *sk;
1407 struct hci_dev *hdev;
1408 u8 mgmt_status;
1409};
1410
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001411static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001412{
1413 struct cmd_lookup *match = data;
1414
1415 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1416
1417 list_del(&cmd->list);
1418
1419 if (match->sk == NULL) {
1420 match->sk = cmd->sk;
1421 sock_hold(match->sk);
1422 }
1423
1424 mgmt_pending_free(cmd);
1425}
1426
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001427static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001428{
1429 u8 *status = data;
1430
Johan Hedberga69e8372015-03-06 21:08:53 +02001431 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001432 mgmt_pending_remove(cmd);
1433}
1434
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001435static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001436{
1437 if (cmd->cmd_complete) {
1438 u8 *status = data;
1439
1440 cmd->cmd_complete(cmd, *status);
1441 mgmt_pending_remove(cmd);
1442
1443 return;
1444 }
1445
1446 cmd_status_rsp(cmd, data);
1447}
1448
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001449static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001450{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001451 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1452 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001453}
1454
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001455static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001456{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001457 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1458 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001459}
1460
Johan Hedberge6fe7982013-10-02 15:45:22 +03001461static u8 mgmt_bredr_support(struct hci_dev *hdev)
1462{
1463 if (!lmp_bredr_capable(hdev))
1464 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001465 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001466 return MGMT_STATUS_REJECTED;
1467 else
1468 return MGMT_STATUS_SUCCESS;
1469}
1470
1471static u8 mgmt_le_support(struct hci_dev *hdev)
1472{
1473 if (!lmp_le_capable(hdev))
1474 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001475 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001476 return MGMT_STATUS_REJECTED;
1477 else
1478 return MGMT_STATUS_SUCCESS;
1479}
1480
Marcel Holtmann1904a852015-01-11 13:50:44 -08001481static void set_discoverable_complete(struct hci_dev *hdev, u8 status,
1482 u16 opcode)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001483{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001484 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001485 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001486 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001487 bool changed;
1488
1489 BT_DBG("status 0x%02x", status);
1490
1491 hci_dev_lock(hdev);
1492
Johan Hedberg333ae952015-03-17 13:48:47 +02001493 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001494 if (!cmd)
1495 goto unlock;
1496
1497 if (status) {
1498 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001499 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001500 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001501 goto remove_cmd;
1502 }
1503
1504 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001505 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001506 changed = !hci_dev_test_and_set_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001507
1508 if (hdev->discov_timeout > 0) {
1509 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1510 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1511 to);
1512 }
1513 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001514 changed = hci_dev_test_and_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001515 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001516
1517 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1518
1519 if (changed)
1520 new_settings(hdev, cmd->sk);
1521
Marcel Holtmann970ba522013-10-15 06:33:57 -07001522 /* When the discoverable mode gets changed, make sure
1523 * that class of device has the limited discoverable
Johan Hedberg432df052014-08-01 11:13:31 +03001524 * bit correctly set. Also update page scan based on whitelist
1525 * entries.
Marcel Holtmann970ba522013-10-15 06:33:57 -07001526 */
1527 hci_req_init(&req, hdev);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001528 __hci_update_page_scan(&req);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001529 update_class(&req);
1530 hci_req_run(&req, NULL);
1531
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001532remove_cmd:
1533 mgmt_pending_remove(cmd);
1534
1535unlock:
1536 hci_dev_unlock(hdev);
1537}
1538
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001539static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001540 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001541{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001542 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001543 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001544 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001545 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001546 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001547 int err;
Johan Hedberge41d8b42010-12-13 21:07:03 +02001548
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001549 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001550
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001551 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1552 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001553 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1554 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001555
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001556 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001557 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1558 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001559
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001560 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001561
1562 /* Disabling discoverable requires that no timeout is set,
1563 * and enabling limited discoverable requires a timeout.
1564 */
1565 if ((cp->val == 0x00 && timeout > 0) ||
1566 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001567 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1568 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001569
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001570 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001571
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001572 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001573 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1574 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001575 goto failed;
1576 }
1577
Johan Hedberg333ae952015-03-17 13:48:47 +02001578 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1579 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001580 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1581 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001582 goto failed;
1583 }
1584
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001585 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001586 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1587 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001588 goto failed;
1589 }
1590
1591 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001592 bool changed = false;
1593
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001594 /* Setting limited discoverable when powered off is
1595 * not a valid operation since it requires a timeout
1596 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1597 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001598 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001599 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001600 changed = true;
1601 }
1602
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001603 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001604 if (err < 0)
1605 goto failed;
1606
1607 if (changed)
1608 err = new_settings(hdev, sk);
1609
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001610 goto failed;
1611 }
1612
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001613 /* If the current mode is the same, then just update the timeout
1614 * value with the new value. And if only the timeout gets updated,
1615 * then no need for any HCI transactions.
1616 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001617 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1618 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1619 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001620 cancel_delayed_work(&hdev->discov_off);
1621 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001622
Marcel Holtmann36261542013-10-15 08:28:51 -07001623 if (cp->val && hdev->discov_timeout > 0) {
1624 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001625 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001626 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001627 }
1628
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001629 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001630 goto failed;
1631 }
1632
1633 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1634 if (!cmd) {
1635 err = -ENOMEM;
1636 goto failed;
1637 }
1638
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001639 /* Cancel any potential discoverable timeout that might be
1640 * still active and store new timeout value. The arming of
1641 * the timeout happens in the complete handler.
1642 */
1643 cancel_delayed_work(&hdev->discov_off);
1644 hdev->discov_timeout = timeout;
1645
Johan Hedbergb456f872013-10-19 23:38:22 +03001646 /* Limited discoverable mode */
1647 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001648 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001649 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001650 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001651
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001652 hci_req_init(&req, hdev);
1653
Johan Hedberg9a43e252013-10-20 19:00:07 +03001654 /* The procedure for LE-only controllers is much simpler - just
1655 * update the advertising data.
1656 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001657 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg9a43e252013-10-20 19:00:07 +03001658 goto update_ad;
1659
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001660 scan = SCAN_PAGE;
1661
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001662 if (cp->val) {
1663 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001664
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001665 if (cp->val == 0x02) {
1666 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001667 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001668 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1669 hci_cp.iac_lap[1] = 0x8b;
1670 hci_cp.iac_lap[2] = 0x9e;
1671 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1672 hci_cp.iac_lap[4] = 0x8b;
1673 hci_cp.iac_lap[5] = 0x9e;
1674 } else {
1675 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001676 hci_cp.num_iac = 1;
1677 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1678 hci_cp.iac_lap[1] = 0x8b;
1679 hci_cp.iac_lap[2] = 0x9e;
1680 }
1681
1682 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1683 (hci_cp.num_iac * 3) + 1, &hci_cp);
1684
1685 scan |= SCAN_INQUIRY;
1686 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001687 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001688 }
1689
1690 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001691
Johan Hedberg9a43e252013-10-20 19:00:07 +03001692update_ad:
1693 update_adv_data(&req);
1694
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001695 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001696 if (err < 0)
1697 mgmt_pending_remove(cmd);
1698
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001699failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001700 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001701 return err;
1702}
1703
Johan Hedberg406d7802013-03-15 17:07:09 -05001704static void write_fast_connectable(struct hci_request *req, bool enable)
1705{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001706 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001707 struct hci_cp_write_page_scan_activity acp;
1708 u8 type;
1709
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001710 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg547003b2013-10-21 16:51:53 +03001711 return;
1712
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001713 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1714 return;
1715
Johan Hedberg406d7802013-03-15 17:07:09 -05001716 if (enable) {
1717 type = PAGE_SCAN_TYPE_INTERLACED;
1718
1719 /* 160 msec page scan interval */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001720 acp.interval = cpu_to_le16(0x0100);
Johan Hedberg406d7802013-03-15 17:07:09 -05001721 } else {
1722 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1723
1724 /* default 1.28 sec page scan */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001725 acp.interval = cpu_to_le16(0x0800);
Johan Hedberg406d7802013-03-15 17:07:09 -05001726 }
1727
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001728 acp.window = cpu_to_le16(0x0012);
Johan Hedberg406d7802013-03-15 17:07:09 -05001729
Johan Hedbergbd98b992013-03-15 17:07:13 -05001730 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1731 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1732 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1733 sizeof(acp), &acp);
1734
1735 if (hdev->page_scan_type != type)
1736 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001737}
1738
Marcel Holtmann1904a852015-01-11 13:50:44 -08001739static void set_connectable_complete(struct hci_dev *hdev, u8 status,
1740 u16 opcode)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001741{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001742 struct mgmt_pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001743 struct mgmt_mode *cp;
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001744 bool conn_changed, discov_changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001745
1746 BT_DBG("status 0x%02x", status);
1747
1748 hci_dev_lock(hdev);
1749
Johan Hedberg333ae952015-03-17 13:48:47 +02001750 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001751 if (!cmd)
1752 goto unlock;
1753
Johan Hedberg37438c12013-10-14 16:20:05 +03001754 if (status) {
1755 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001756 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001757 goto remove_cmd;
1758 }
1759
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001760 cp = cmd->param;
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001761 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001762 conn_changed = !hci_dev_test_and_set_flag(hdev,
1763 HCI_CONNECTABLE);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001764 discov_changed = false;
1765 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001766 conn_changed = hci_dev_test_and_clear_flag(hdev,
1767 HCI_CONNECTABLE);
1768 discov_changed = hci_dev_test_and_clear_flag(hdev,
1769 HCI_DISCOVERABLE);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001770 }
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001771
Johan Hedberg2b76f452013-03-15 17:07:04 -05001772 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1773
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001774 if (conn_changed || discov_changed) {
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001775 new_settings(hdev, cmd->sk);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001776 hci_update_page_scan(hdev);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001777 if (discov_changed)
1778 mgmt_update_adv_data(hdev);
Johan Hedberg2b7be332014-07-07 14:40:22 +03001779 hci_update_background_scan(hdev);
1780 }
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001781
Johan Hedberg37438c12013-10-14 16:20:05 +03001782remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001783 mgmt_pending_remove(cmd);
1784
1785unlock:
1786 hci_dev_unlock(hdev);
1787}
1788
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001789static int set_connectable_update_settings(struct hci_dev *hdev,
1790 struct sock *sk, u8 val)
1791{
1792 bool changed = false;
1793 int err;
1794
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001795 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001796 changed = true;
1797
1798 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001799 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001800 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001801 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1802 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001803 }
1804
1805 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1806 if (err < 0)
1807 return err;
1808
Johan Hedberg562064e2014-07-08 16:35:34 +03001809 if (changed) {
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001810 hci_update_page_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001811 hci_update_background_scan(hdev);
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001812 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001813 }
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001814
1815 return 0;
1816}
1817
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001818static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001819 u16 len)
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001820{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001821 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001822 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001823 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001824 u8 scan;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001825 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001826
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001827 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001828
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001829 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1830 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001831 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1832 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001833
Johan Hedberga7e80f22013-01-09 16:05:19 +02001834 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001835 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1836 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001837
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001838 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001839
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001840 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001841 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001842 goto failed;
1843 }
1844
Johan Hedberg333ae952015-03-17 13:48:47 +02001845 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1846 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001847 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1848 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001849 goto failed;
1850 }
1851
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001852 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1853 if (!cmd) {
1854 err = -ENOMEM;
1855 goto failed;
1856 }
1857
Johan Hedberg2b76f452013-03-15 17:07:04 -05001858 hci_req_init(&req, hdev);
1859
Johan Hedberg9a43e252013-10-20 19:00:07 +03001860 /* If BR/EDR is not enabled and we disable advertising as a
1861 * by-product of disabling connectable, we need to update the
1862 * advertising flags.
1863 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001864 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg9a43e252013-10-20 19:00:07 +03001865 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001866 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1867 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg9a43e252013-10-20 19:00:07 +03001868 }
1869 update_adv_data(&req);
1870 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001871 if (cp->val) {
1872 scan = SCAN_PAGE;
1873 } else {
Johan Hedberg3bd27242014-07-28 20:53:58 +03001874 /* If we don't have any whitelist entries just
1875 * disable all scanning. If there are entries
1876 * and we had both page and inquiry scanning
1877 * enabled then fall back to only page scanning.
1878 * Otherwise no changes are needed.
1879 */
1880 if (list_empty(&hdev->whitelist))
1881 scan = SCAN_DISABLED;
1882 else if (test_bit(HCI_ISCAN, &hdev->flags))
1883 scan = SCAN_PAGE;
1884 else
1885 goto no_scan_update;
Johan Hedberg9b742462013-10-14 16:20:03 +03001886
1887 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001888 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001889 cancel_delayed_work(&hdev->discov_off);
1890 }
1891
1892 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1893 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001894
Johan Hedberg3bd27242014-07-28 20:53:58 +03001895no_scan_update:
Johan Hedberge8b12022014-07-10 10:51:27 +03001896 /* Update the advertising parameters if necessary */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001897 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001898 enable_advertising(&req);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001899
Johan Hedberg2b76f452013-03-15 17:07:04 -05001900 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001901 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001902 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001903 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03001904 err = set_connectable_update_settings(hdev, sk,
1905 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03001906 goto failed;
1907 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001908
1909failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001910 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001911 return err;
1912}
1913
Johan Hedbergb2939472014-07-30 09:22:23 +03001914static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001915 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001916{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001917 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001918 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001919 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001920
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001921 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001922
Johan Hedberga7e80f22013-01-09 16:05:19 +02001923 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001924 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
1925 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001926
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001927 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001928
1929 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07001930 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001931 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001932 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001933
Johan Hedbergb2939472014-07-30 09:22:23 +03001934 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001935 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001936 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001937
Marcel Holtmann55594352013-10-06 16:11:57 -07001938 if (changed)
1939 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001940
Marcel Holtmann55594352013-10-06 16:11:57 -07001941unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001942 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001943 return err;
1944}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001945
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001946static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1947 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001948{
1949 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001950 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001951 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001952 int err;
1953
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001954 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001955
Johan Hedberge6fe7982013-10-02 15:45:22 +03001956 status = mgmt_bredr_support(hdev);
1957 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02001958 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1959 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001960
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_LINK_SECURITY,
1963 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001964
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001965 hci_dev_lock(hdev);
1966
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001967 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001968 bool changed = false;
1969
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001970 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001971 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02001972 changed = true;
1973 }
1974
1975 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1976 if (err < 0)
1977 goto failed;
1978
1979 if (changed)
1980 err = new_settings(hdev, sk);
1981
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001982 goto failed;
1983 }
1984
Johan Hedberg333ae952015-03-17 13:48:47 +02001985 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001986 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1987 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001988 goto failed;
1989 }
1990
1991 val = !!cp->val;
1992
1993 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1994 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1995 goto failed;
1996 }
1997
1998 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1999 if (!cmd) {
2000 err = -ENOMEM;
2001 goto failed;
2002 }
2003
2004 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
2005 if (err < 0) {
2006 mgmt_pending_remove(cmd);
2007 goto failed;
2008 }
2009
2010failed:
2011 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002012 return err;
2013}
2014
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002015static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002016{
2017 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002018 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07002019 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002020 int err;
2021
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002022 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002023
Marcel Holtmanncdba5282013-10-02 21:31:52 -07002024 status = mgmt_bredr_support(hdev);
2025 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002026 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07002027
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002028 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002029 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2030 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002031
Johan Hedberga7e80f22013-01-09 16:05:19 +02002032 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002033 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2034 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002035
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002036 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02002037
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002038 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002039 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02002040
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002041 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07002042 changed = !hci_dev_test_and_set_flag(hdev,
2043 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002044 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002045 changed = hci_dev_test_and_clear_flag(hdev,
2046 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002047 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002048 changed = hci_dev_test_and_clear_flag(hdev,
2049 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002050 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002051 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02002052 }
2053
2054 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
2055 if (err < 0)
2056 goto failed;
2057
2058 if (changed)
2059 err = new_settings(hdev, sk);
2060
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002061 goto failed;
2062 }
2063
Johan Hedberg333ae952015-03-17 13:48:47 +02002064 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002065 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2066 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002067 goto failed;
2068 }
2069
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002070 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002071 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
2072 goto failed;
2073 }
2074
2075 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
2076 if (!cmd) {
2077 err = -ENOMEM;
2078 goto failed;
2079 }
2080
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002081 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03002082 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
2083 sizeof(cp->val), &cp->val);
2084
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07002085 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002086 if (err < 0) {
2087 mgmt_pending_remove(cmd);
2088 goto failed;
2089 }
2090
2091failed:
2092 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002093 return err;
2094}
2095
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002096static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002097{
2098 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07002099 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03002100 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07002101 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002102
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002103 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002104
Johan Hedberge6fe7982013-10-02 15:45:22 +03002105 status = mgmt_bredr_support(hdev);
2106 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002107 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002108
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002109 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002110 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2111 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002112
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002113 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02002114 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2115 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002116
Johan Hedberga7e80f22013-01-09 16:05:19 +02002117 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002118 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2119 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002120
Marcel Holtmannee392692013-10-01 22:59:23 -07002121 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002122
Johan Hedberg333ae952015-03-17 13:48:47 +02002123 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002124 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2125 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02002126 goto unlock;
2127 }
2128
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002129 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07002130 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002131 } else {
2132 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002133 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2134 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002135 goto unlock;
2136 }
2137
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002138 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002139 }
Marcel Holtmannee392692013-10-01 22:59:23 -07002140
2141 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
2142 if (err < 0)
2143 goto unlock;
2144
2145 if (changed)
2146 err = new_settings(hdev, sk);
2147
2148unlock:
2149 hci_dev_unlock(hdev);
2150 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002151}
2152
Marcel Holtmann1904a852015-01-11 13:50:44 -08002153static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002154{
2155 struct cmd_lookup match = { NULL, hdev };
2156
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302157 hci_dev_lock(hdev);
2158
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002159 if (status) {
2160 u8 mgmt_err = mgmt_status(status);
2161
2162 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
2163 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302164 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002165 }
2166
2167 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
2168
2169 new_settings(hdev, match.sk);
2170
2171 if (match.sk)
2172 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002173
2174 /* Make sure the controller has a good default for
2175 * advertising data. Restrict the update to when LE
2176 * has actually been enabled. During power on, the
2177 * update in powered_update_hci will take care of it.
2178 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002179 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002180 struct hci_request req;
2181
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002182 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07002183 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07002184 update_scan_rsp_data(&req);
Johan Hedberg2cf22212014-12-19 22:26:00 +02002185 __hci_update_background_scan(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002186 hci_req_run(&req, NULL);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002187 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302188
2189unlock:
2190 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002191}
2192
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002193static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002194{
2195 struct mgmt_mode *cp = data;
2196 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002197 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002198 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002199 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002200 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002201
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002202 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002203
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002204 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002205 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2206 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002207
Johan Hedberga7e80f22013-01-09 16:05:19 +02002208 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002209 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2210 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002211
Johan Hedbergc73eee92013-04-19 18:35:21 +03002212 /* LE-only devices do not allow toggling LE on/off */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002213 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02002214 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2215 MGMT_STATUS_REJECTED);
Johan Hedbergc73eee92013-04-19 18:35:21 +03002216
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002217 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002218
2219 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02002220 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002221
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002222 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02002223 bool changed = false;
2224
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002225 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07002226 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002227 changed = true;
2228 }
2229
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002230 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002231 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03002232 changed = true;
2233 }
2234
Johan Hedberg06199cf2012-02-22 16:37:11 +02002235 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
2236 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08002237 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002238
2239 if (changed)
2240 err = new_settings(hdev, sk);
2241
Johan Hedberg1de028c2012-02-29 19:55:35 -08002242 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002243 }
2244
Johan Hedberg333ae952015-03-17 13:48:47 +02002245 if (pending_find(MGMT_OP_SET_LE, hdev) ||
2246 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002247 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2248 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002249 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002250 }
2251
2252 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
2253 if (!cmd) {
2254 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08002255 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002256 }
2257
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002258 hci_req_init(&req, hdev);
2259
Johan Hedberg06199cf2012-02-22 16:37:11 +02002260 memset(&hci_cp, 0, sizeof(hci_cp));
2261
2262 if (val) {
2263 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02002264 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002265 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002266 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002267 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002268 }
2269
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002270 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
2271 &hci_cp);
2272
2273 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05302274 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002275 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002276
Johan Hedberg1de028c2012-02-29 19:55:35 -08002277unlock:
2278 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002279 return err;
2280}
2281
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002282/* This is a helper function to test for pending mgmt commands that can
2283 * cause CoD or EIR HCI commands. We can only allow one such pending
2284 * mgmt command at a time since otherwise we cannot easily track what
2285 * the current values are, will be, and based on that calculate if a new
2286 * HCI command needs to be sent and if yes with what value.
2287 */
2288static bool pending_eir_or_class(struct hci_dev *hdev)
2289{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002290 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002291
2292 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2293 switch (cmd->opcode) {
2294 case MGMT_OP_ADD_UUID:
2295 case MGMT_OP_REMOVE_UUID:
2296 case MGMT_OP_SET_DEV_CLASS:
2297 case MGMT_OP_SET_POWERED:
2298 return true;
2299 }
2300 }
2301
2302 return false;
2303}
2304
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002305static const u8 bluetooth_base_uuid[] = {
2306 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2307 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2308};
2309
2310static u8 get_uuid_size(const u8 *uuid)
2311{
2312 u32 val;
2313
2314 if (memcmp(uuid, bluetooth_base_uuid, 12))
2315 return 128;
2316
2317 val = get_unaligned_le32(&uuid[12]);
2318 if (val > 0xffff)
2319 return 32;
2320
2321 return 16;
2322}
2323
Johan Hedberg92da6092013-03-15 17:06:55 -05002324static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2325{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002326 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002327
2328 hci_dev_lock(hdev);
2329
Johan Hedberg333ae952015-03-17 13:48:47 +02002330 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002331 if (!cmd)
2332 goto unlock;
2333
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002334 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2335 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002336
2337 mgmt_pending_remove(cmd);
2338
2339unlock:
2340 hci_dev_unlock(hdev);
2341}
2342
Marcel Holtmann1904a852015-01-11 13:50:44 -08002343static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002344{
2345 BT_DBG("status 0x%02x", status);
2346
2347 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2348}
2349
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002350static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002351{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002352 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002353 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002354 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002355 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002356 int err;
2357
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002358 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002359
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002360 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002361
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002362 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002363 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2364 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002365 goto failed;
2366 }
2367
Andre Guedes92c4c202012-06-07 19:05:44 -03002368 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002369 if (!uuid) {
2370 err = -ENOMEM;
2371 goto failed;
2372 }
2373
2374 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002375 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002376 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002377
Johan Hedbergde66aa62013-01-27 00:31:27 +02002378 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002379
Johan Hedberg890ea892013-03-15 17:06:52 -05002380 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002381
Johan Hedberg890ea892013-03-15 17:06:52 -05002382 update_class(&req);
2383 update_eir(&req);
2384
Johan Hedberg92da6092013-03-15 17:06:55 -05002385 err = hci_req_run(&req, add_uuid_complete);
2386 if (err < 0) {
2387 if (err != -ENODATA)
2388 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002389
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002390 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2391 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002392 goto failed;
2393 }
2394
2395 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002396 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002397 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002398 goto failed;
2399 }
2400
2401 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002402
2403failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002404 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002405 return err;
2406}
2407
Johan Hedberg24b78d02012-02-23 23:24:30 +02002408static bool enable_service_cache(struct hci_dev *hdev)
2409{
2410 if (!hdev_is_powered(hdev))
2411 return false;
2412
Marcel Holtmann238be782015-03-13 02:11:06 -07002413 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002414 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2415 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002416 return true;
2417 }
2418
2419 return false;
2420}
2421
Marcel Holtmann1904a852015-01-11 13:50:44 -08002422static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002423{
2424 BT_DBG("status 0x%02x", status);
2425
2426 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2427}
2428
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002429static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002430 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002431{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002432 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002433 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002434 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002435 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 -05002436 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002437 int err, found;
2438
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002439 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002440
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002441 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002442
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002443 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002444 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2445 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002446 goto unlock;
2447 }
2448
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002449 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002450 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002451
Johan Hedberg24b78d02012-02-23 23:24:30 +02002452 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002453 err = mgmt_cmd_complete(sk, hdev->id,
2454 MGMT_OP_REMOVE_UUID,
2455 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002456 goto unlock;
2457 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002458
Johan Hedberg9246a862012-02-23 21:33:16 +02002459 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002460 }
2461
2462 found = 0;
2463
Johan Hedberg056341c2013-01-27 00:31:30 +02002464 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002465 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2466 continue;
2467
2468 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002469 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002470 found++;
2471 }
2472
2473 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002474 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2475 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002476 goto unlock;
2477 }
2478
Johan Hedberg9246a862012-02-23 21:33:16 +02002479update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002480 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002481
Johan Hedberg890ea892013-03-15 17:06:52 -05002482 update_class(&req);
2483 update_eir(&req);
2484
Johan Hedberg92da6092013-03-15 17:06:55 -05002485 err = hci_req_run(&req, remove_uuid_complete);
2486 if (err < 0) {
2487 if (err != -ENODATA)
2488 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002489
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002490 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2491 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002492 goto unlock;
2493 }
2494
2495 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002496 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002497 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002498 goto unlock;
2499 }
2500
2501 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002502
2503unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002504 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002505 return err;
2506}
2507
Marcel Holtmann1904a852015-01-11 13:50:44 -08002508static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002509{
2510 BT_DBG("status 0x%02x", status);
2511
2512 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2513}
2514
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002515static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002516 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002517{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002518 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002519 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002520 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002521 int err;
2522
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002523 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002524
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002525 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002526 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2527 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002528
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002529 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002530
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002531 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002532 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2533 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002534 goto unlock;
2535 }
2536
2537 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002538 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2539 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002540 goto unlock;
2541 }
2542
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002543 hdev->major_class = cp->major;
2544 hdev->minor_class = cp->minor;
2545
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002546 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002547 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2548 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002549 goto unlock;
2550 }
2551
Johan Hedberg890ea892013-03-15 17:06:52 -05002552 hci_req_init(&req, hdev);
2553
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002554 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002555 hci_dev_unlock(hdev);
2556 cancel_delayed_work_sync(&hdev->service_cache);
2557 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002558 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002559 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002560
Johan Hedberg890ea892013-03-15 17:06:52 -05002561 update_class(&req);
2562
Johan Hedberg92da6092013-03-15 17:06:55 -05002563 err = hci_req_run(&req, set_class_complete);
2564 if (err < 0) {
2565 if (err != -ENODATA)
2566 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002567
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002568 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2569 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002570 goto unlock;
2571 }
2572
2573 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002574 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002575 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002576 goto unlock;
2577 }
2578
2579 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002580
Johan Hedbergb5235a62012-02-21 14:32:24 +02002581unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002582 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002583 return err;
2584}
2585
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002586static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002587 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002588{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002589 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002590 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2591 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002592 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002593 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002594 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002595
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002596 BT_DBG("request for %s", hdev->name);
2597
2598 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002599 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2600 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002601
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002602 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002603 if (key_count > max_key_count) {
2604 BT_ERR("load_link_keys: too big key_count value %u",
2605 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002606 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2607 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002608 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002609
Johan Hedberg86742e12011-11-07 23:13:38 +02002610 expected_len = sizeof(*cp) + key_count *
2611 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002612 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002613 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002614 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002615 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2616 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002617 }
2618
Johan Hedberg4ae143012013-01-20 14:27:13 +02002619 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002620 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2621 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae143012013-01-20 14:27:13 +02002622
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002623 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002624 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002625
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002626 for (i = 0; i < key_count; i++) {
2627 struct mgmt_link_key_info *key = &cp->keys[i];
2628
Marcel Holtmann8e991132014-01-10 02:07:25 -08002629 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002630 return mgmt_cmd_status(sk, hdev->id,
2631 MGMT_OP_LOAD_LINK_KEYS,
2632 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002633 }
2634
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002635 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002636
2637 hci_link_keys_clear(hdev);
2638
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002639 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002640 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002641 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002642 changed = hci_dev_test_and_clear_flag(hdev,
2643 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002644
2645 if (changed)
2646 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002647
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002648 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002649 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002650
Johan Hedberg58e92932014-06-24 14:00:26 +03002651 /* Always ignore debug keys and require a new pairing if
2652 * the user wants to use them.
2653 */
2654 if (key->type == HCI_LK_DEBUG_COMBINATION)
2655 continue;
2656
Johan Hedberg7652ff62014-06-24 13:15:49 +03002657 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2658 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002659 }
2660
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002661 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002662
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002663 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002664
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002665 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002666}
2667
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002668static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002669 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002670{
2671 struct mgmt_ev_device_unpaired ev;
2672
2673 bacpy(&ev.addr.bdaddr, bdaddr);
2674 ev.addr.type = addr_type;
2675
2676 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002677 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002678}
2679
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002680static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002681 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002682{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002683 struct mgmt_cp_unpair_device *cp = data;
2684 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002685 struct hci_cp_disconnect dc;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002686 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002687 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002688 int err;
2689
Johan Hedberga8a1d192011-11-10 15:54:38 +02002690 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002691 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2692 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002693
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002694 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002695 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2696 MGMT_STATUS_INVALID_PARAMS,
2697 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002698
Johan Hedberg118da702013-01-20 14:27:20 +02002699 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002700 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2701 MGMT_STATUS_INVALID_PARAMS,
2702 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002703
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002704 hci_dev_lock(hdev);
2705
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002706 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002707 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2708 MGMT_STATUS_NOT_POWERED, &rp,
2709 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002710 goto unlock;
2711 }
2712
Johan Hedberge0b2b272014-02-18 17:14:31 +02002713 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002714 /* If disconnection is requested, then look up the
2715 * connection. If the remote device is connected, it
2716 * will be later used to terminate the link.
2717 *
2718 * Setting it to NULL explicitly will cause no
2719 * termination of the link.
2720 */
2721 if (cp->disconnect)
2722 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2723 &cp->addr.bdaddr);
2724 else
2725 conn = NULL;
2726
Johan Hedberg124f6e32012-02-09 13:50:12 +02002727 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedberge0b2b272014-02-18 17:14:31 +02002728 } else {
2729 u8 addr_type;
2730
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002731 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
2732 &cp->addr.bdaddr);
2733 if (conn) {
2734 /* Defer clearing up the connection parameters
2735 * until closing to give a chance of keeping
2736 * them if a repairing happens.
2737 */
2738 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2739
2740 /* If disconnection is not requested, then
2741 * clear the connection variable so that the
2742 * link is not terminated.
2743 */
2744 if (!cp->disconnect)
2745 conn = NULL;
2746 }
2747
Johan Hedberge0b2b272014-02-18 17:14:31 +02002748 if (cp->addr.type == BDADDR_LE_PUBLIC)
2749 addr_type = ADDR_LE_DEV_PUBLIC;
2750 else
2751 addr_type = ADDR_LE_DEV_RANDOM;
2752
Johan Hedberga7ec7332014-02-18 17:14:35 +02002753 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2754
Johan Hedberge0b2b272014-02-18 17:14:31 +02002755 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
2756 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002757
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002758 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002759 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2760 MGMT_STATUS_NOT_PAIRED, &rp,
2761 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002762 goto unlock;
2763 }
2764
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002765 /* If the connection variable is set, then termination of the
2766 * link is requested.
2767 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002768 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002769 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2770 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002771 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002772 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002773 }
2774
Johan Hedberg124f6e32012-02-09 13:50:12 +02002775 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002776 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002777 if (!cmd) {
2778 err = -ENOMEM;
2779 goto unlock;
2780 }
2781
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002782 cmd->cmd_complete = addr_cmd_complete;
2783
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002784 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002785 dc.reason = 0x13; /* Remote User Terminated Connection */
2786 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2787 if (err < 0)
2788 mgmt_pending_remove(cmd);
2789
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002790unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002791 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002792 return err;
2793}
2794
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002795static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002796 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002797{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002798 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002799 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002800 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002801 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002802 int err;
2803
2804 BT_DBG("");
2805
Johan Hedberg06a63b12013-01-20 14:27:21 +02002806 memset(&rp, 0, sizeof(rp));
2807 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2808 rp.addr.type = cp->addr.type;
2809
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002810 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002811 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2812 MGMT_STATUS_INVALID_PARAMS,
2813 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002814
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002815 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002816
2817 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002818 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2819 MGMT_STATUS_NOT_POWERED, &rp,
2820 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002821 goto failed;
2822 }
2823
Johan Hedberg333ae952015-03-17 13:48:47 +02002824 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002825 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2826 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002827 goto failed;
2828 }
2829
Andre Guedes591f47f2012-04-24 21:02:49 -03002830 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002831 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2832 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002833 else
2834 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002835
Vishal Agarwalf9607272012-06-13 05:32:43 +05302836 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002837 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2838 MGMT_STATUS_NOT_CONNECTED, &rp,
2839 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002840 goto failed;
2841 }
2842
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002843 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002844 if (!cmd) {
2845 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002846 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002847 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002848
Johan Hedbergf5818c22014-12-05 13:36:02 +02002849 cmd->cmd_complete = generic_cmd_complete;
2850
Johan Hedberge3f2f922014-08-18 20:33:33 +03002851 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002852 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002853 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002854
2855failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002856 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002857 return err;
2858}
2859
Andre Guedes57c14772012-04-24 21:02:50 -03002860static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002861{
2862 switch (link_type) {
2863 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002864 switch (addr_type) {
2865 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002866 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002867
Johan Hedberg48264f02011-11-09 13:58:58 +02002868 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002869 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002870 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002871 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002872
Johan Hedberg4c659c32011-11-07 23:13:39 +02002873 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002874 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002875 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002876 }
2877}
2878
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002879static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2880 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002881{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002882 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002883 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002884 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002885 int err;
2886 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002887
2888 BT_DBG("");
2889
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002890 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002891
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002892 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002893 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2894 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002895 goto unlock;
2896 }
2897
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002898 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002899 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2900 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002901 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002902 }
2903
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002904 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002905 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002906 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002907 err = -ENOMEM;
2908 goto unlock;
2909 }
2910
Johan Hedberg2784eb42011-01-21 13:56:35 +02002911 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002912 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002913 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2914 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002915 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002916 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002917 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002918 continue;
2919 i++;
2920 }
2921
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002922 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002923
Johan Hedberg4c659c32011-11-07 23:13:39 +02002924 /* Recalculate length in case of filtered SCO connections, etc */
2925 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002926
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002927 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
2928 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002929
Johan Hedberga38528f2011-01-22 06:46:43 +02002930 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002931
2932unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002933 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002934 return err;
2935}
2936
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002937static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002938 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002939{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002940 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002941 int err;
2942
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002943 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002944 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002945 if (!cmd)
2946 return -ENOMEM;
2947
Johan Hedbergd8457692012-02-17 14:24:57 +02002948 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002949 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002950 if (err < 0)
2951 mgmt_pending_remove(cmd);
2952
2953 return err;
2954}
2955
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002956static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002957 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002958{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002959 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002960 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002961 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002962 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002963 int err;
2964
2965 BT_DBG("");
2966
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002967 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002968
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002969 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002970 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2971 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002972 goto failed;
2973 }
2974
Johan Hedbergd8457692012-02-17 14:24:57 +02002975 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002976 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002977 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2978 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002979 goto failed;
2980 }
2981
2982 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002983 struct mgmt_cp_pin_code_neg_reply ncp;
2984
2985 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002986
2987 BT_ERR("PIN code is not 16 bytes long");
2988
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002989 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002990 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02002991 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
2992 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002993
2994 goto failed;
2995 }
2996
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002997 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002998 if (!cmd) {
2999 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003000 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03003001 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02003002
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003003 cmd->cmd_complete = addr_cmd_complete;
3004
Johan Hedbergd8457692012-02-17 14:24:57 +02003005 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003006 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02003007 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003008
3009 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
3010 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03003011 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003012
3013failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003014 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003015 return err;
3016}
3017
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003018static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
3019 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003020{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003021 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003022
3023 BT_DBG("");
3024
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003025 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003026 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
3027 MGMT_STATUS_INVALID_PARAMS, NULL, 0);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003028
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003029 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003030
3031 hdev->io_capability = cp->io_capability;
3032
3033 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003034 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003035
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003036 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003037
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003038 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
3039 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003040}
3041
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003042static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003043{
3044 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003045 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003046
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003047 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03003048 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
3049 continue;
3050
Johan Hedberge9a416b2011-02-19 12:05:56 -03003051 if (cmd->user_data != conn)
3052 continue;
3053
3054 return cmd;
3055 }
3056
3057 return NULL;
3058}
3059
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003060static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003061{
3062 struct mgmt_rp_pair_device rp;
3063 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02003064 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003065
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02003066 bacpy(&rp.addr.bdaddr, &conn->dst);
3067 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003068
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003069 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
3070 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003071
3072 /* So we don't get further callbacks for this connection */
3073 conn->connect_cfm_cb = NULL;
3074 conn->security_cfm_cb = NULL;
3075 conn->disconn_cfm_cb = NULL;
3076
David Herrmann76a68ba2013-04-06 20:28:37 +02003077 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00003078
3079 /* The device is paired so there is no need to remove
3080 * its connection parameters anymore.
3081 */
3082 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02003083
3084 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02003085
3086 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003087}
3088
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003089void mgmt_smp_complete(struct hci_conn *conn, bool complete)
3090{
3091 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003092 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003093
3094 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003095 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02003096 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02003097 mgmt_pending_remove(cmd);
3098 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003099}
3100
Johan Hedberge9a416b2011-02-19 12:05:56 -03003101static void pairing_complete_cb(struct hci_conn *conn, u8 status)
3102{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003103 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003104
3105 BT_DBG("status %u", status);
3106
Johan Hedberg56e5cb82011-11-08 20:40:16 +02003107 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003108 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02003109 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02003110 return;
3111 }
3112
3113 cmd->cmd_complete(cmd, mgmt_status(status));
3114 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003115}
3116
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003117static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303118{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003119 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303120
3121 BT_DBG("status %u", status);
3122
3123 if (!status)
3124 return;
3125
3126 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003127 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303128 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02003129 return;
3130 }
3131
3132 cmd->cmd_complete(cmd, mgmt_status(status));
3133 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303134}
3135
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003136static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003137 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003138{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003139 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02003140 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003141 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003142 u8 sec_level, auth_type;
3143 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003144 int err;
3145
3146 BT_DBG("");
3147
Szymon Jancf950a30e2013-01-18 12:48:07 +01003148 memset(&rp, 0, sizeof(rp));
3149 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3150 rp.addr.type = cp->addr.type;
3151
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003152 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003153 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3154 MGMT_STATUS_INVALID_PARAMS,
3155 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003156
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003157 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003158 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3159 MGMT_STATUS_INVALID_PARAMS,
3160 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003161
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003162 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003163
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003164 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003165 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3166 MGMT_STATUS_NOT_POWERED, &rp,
3167 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003168 goto unlock;
3169 }
3170
Johan Hedberg55e76b32015-03-10 22:34:40 +02003171 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
3172 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3173 MGMT_STATUS_ALREADY_PAIRED, &rp,
3174 sizeof(rp));
3175 goto unlock;
3176 }
3177
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03003178 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02003179 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003180
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003181 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03003182 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
3183 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003184 } else {
3185 u8 addr_type;
3186
3187 /* Convert from L2CAP channel address type to HCI address type
3188 */
3189 if (cp->addr.type == BDADDR_LE_PUBLIC)
3190 addr_type = ADDR_LE_DEV_PUBLIC;
3191 else
3192 addr_type = ADDR_LE_DEV_RANDOM;
3193
Marcel Holtmann7c264b12014-06-30 12:34:40 +02003194 /* When pairing a new device, it is expected to remember
3195 * this device for future connections. Adding the connection
3196 * parameter information ahead of time allows tracking
3197 * of the slave preferred values and will speed up any
3198 * further connection establishment.
3199 *
3200 * If connection parameters already exist, then they
3201 * will be kept and this function does nothing.
3202 */
3203 hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
3204
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003205 conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type,
Johan Hedberge804d252014-07-16 11:42:28 +03003206 sec_level, HCI_LE_CONN_TIMEOUT,
3207 HCI_ROLE_MASTER);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003208 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003209
Ville Tervo30e76272011-02-22 16:10:53 -03003210 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003211 int status;
3212
3213 if (PTR_ERR(conn) == -EBUSY)
3214 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01003215 else if (PTR_ERR(conn) == -EOPNOTSUPP)
3216 status = MGMT_STATUS_NOT_SUPPORTED;
3217 else if (PTR_ERR(conn) == -ECONNREFUSED)
3218 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003219 else
3220 status = MGMT_STATUS_CONNECT_FAILED;
3221
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003222 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3223 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003224 goto unlock;
3225 }
3226
3227 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02003228 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003229 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3230 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003231 goto unlock;
3232 }
3233
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003234 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003235 if (!cmd) {
3236 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02003237 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003238 goto unlock;
3239 }
3240
Johan Hedberg04ab2742014-12-05 13:36:04 +02003241 cmd->cmd_complete = pairing_complete;
3242
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003243 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003244 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003245 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003246 conn->security_cfm_cb = pairing_complete_cb;
3247 conn->disconn_cfm_cb = pairing_complete_cb;
3248 } else {
3249 conn->connect_cfm_cb = le_pairing_complete_cb;
3250 conn->security_cfm_cb = le_pairing_complete_cb;
3251 conn->disconn_cfm_cb = le_pairing_complete_cb;
3252 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003253
Johan Hedberge9a416b2011-02-19 12:05:56 -03003254 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003255 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003256
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003257 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003258 hci_conn_security(conn, sec_level, auth_type, true)) {
3259 cmd->cmd_complete(cmd, 0);
3260 mgmt_pending_remove(cmd);
3261 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003262
3263 err = 0;
3264
3265unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003266 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003267 return err;
3268}
3269
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003270static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3271 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003272{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003273 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003274 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003275 struct hci_conn *conn;
3276 int err;
3277
3278 BT_DBG("");
3279
Johan Hedberg28424702012-02-02 04:02:29 +02003280 hci_dev_lock(hdev);
3281
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003282 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003283 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3284 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003285 goto unlock;
3286 }
3287
Johan Hedberg333ae952015-03-17 13:48:47 +02003288 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003289 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003290 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3291 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003292 goto unlock;
3293 }
3294
3295 conn = cmd->user_data;
3296
3297 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003298 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3299 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003300 goto unlock;
3301 }
3302
Johan Hedberga511b352014-12-11 21:45:45 +02003303 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3304 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003305
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003306 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3307 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003308unlock:
3309 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003310 return err;
3311}
3312
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003313static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003314 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003315 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003316{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003317 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003318 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003319 int err;
3320
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003321 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003322
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003323 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003324 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3325 MGMT_STATUS_NOT_POWERED, addr,
3326 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003327 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003328 }
3329
Johan Hedberg1707c602013-03-15 17:07:15 -05003330 if (addr->type == BDADDR_BREDR)
3331 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003332 else
Johan Hedberg1707c602013-03-15 17:07:15 -05003333 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08003334
Johan Hedberg272d90d2012-02-09 15:26:12 +02003335 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003336 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3337 MGMT_STATUS_NOT_CONNECTED, addr,
3338 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003339 goto done;
3340 }
3341
Johan Hedberg1707c602013-03-15 17:07:15 -05003342 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003343 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003344 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003345 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3346 MGMT_STATUS_SUCCESS, addr,
3347 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003348 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003349 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3350 MGMT_STATUS_FAILED, addr,
3351 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003352
Brian Gix47c15e22011-11-16 13:53:14 -08003353 goto done;
3354 }
3355
Johan Hedberg1707c602013-03-15 17:07:15 -05003356 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003357 if (!cmd) {
3358 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003359 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003360 }
3361
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003362 cmd->cmd_complete = addr_cmd_complete;
3363
Brian Gix0df4c182011-11-16 13:53:13 -08003364 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003365 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3366 struct hci_cp_user_passkey_reply cp;
3367
Johan Hedberg1707c602013-03-15 17:07:15 -05003368 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003369 cp.passkey = passkey;
3370 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3371 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003372 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3373 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003374
Johan Hedberga664b5b2011-02-19 12:06:02 -03003375 if (err < 0)
3376 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003377
Brian Gix0df4c182011-11-16 13:53:13 -08003378done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003379 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003380 return err;
3381}
3382
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303383static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3384 void *data, u16 len)
3385{
3386 struct mgmt_cp_pin_code_neg_reply *cp = data;
3387
3388 BT_DBG("");
3389
Johan Hedberg1707c602013-03-15 17:07:15 -05003390 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303391 MGMT_OP_PIN_CODE_NEG_REPLY,
3392 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3393}
3394
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003395static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3396 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003397{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003398 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003399
3400 BT_DBG("");
3401
3402 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003403 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3404 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003405
Johan Hedberg1707c602013-03-15 17:07:15 -05003406 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003407 MGMT_OP_USER_CONFIRM_REPLY,
3408 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003409}
3410
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003411static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003412 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003413{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003414 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003415
3416 BT_DBG("");
3417
Johan Hedberg1707c602013-03-15 17:07:15 -05003418 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003419 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3420 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003421}
3422
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003423static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3424 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003425{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003426 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003427
3428 BT_DBG("");
3429
Johan Hedberg1707c602013-03-15 17:07:15 -05003430 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003431 MGMT_OP_USER_PASSKEY_REPLY,
3432 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003433}
3434
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003435static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003436 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003437{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003438 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003439
3440 BT_DBG("");
3441
Johan Hedberg1707c602013-03-15 17:07:15 -05003442 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003443 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3444 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003445}
3446
Johan Hedberg13928972013-03-15 17:07:00 -05003447static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003448{
Johan Hedberg13928972013-03-15 17:07:00 -05003449 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003450 struct hci_cp_write_local_name cp;
3451
Johan Hedberg13928972013-03-15 17:07:00 -05003452 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003453
Johan Hedberg890ea892013-03-15 17:06:52 -05003454 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003455}
3456
Marcel Holtmann1904a852015-01-11 13:50:44 -08003457static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003458{
3459 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003460 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003461
3462 BT_DBG("status 0x%02x", status);
3463
3464 hci_dev_lock(hdev);
3465
Johan Hedberg333ae952015-03-17 13:48:47 +02003466 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003467 if (!cmd)
3468 goto unlock;
3469
3470 cp = cmd->param;
3471
3472 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003473 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3474 mgmt_status(status));
Johan Hedberg13928972013-03-15 17:07:00 -05003475 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003476 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3477 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003478
3479 mgmt_pending_remove(cmd);
3480
3481unlock:
3482 hci_dev_unlock(hdev);
3483}
3484
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003485static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003486 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003487{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003488 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003489 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003490 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003491 int err;
3492
3493 BT_DBG("");
3494
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003495 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003496
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003497 /* If the old values are the same as the new ones just return a
3498 * direct command complete event.
3499 */
3500 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3501 !memcmp(hdev->short_name, cp->short_name,
3502 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003503 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3504 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003505 goto failed;
3506 }
3507
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003508 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003509
Johan Hedbergb5235a62012-02-21 14:32:24 +02003510 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003511 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003512
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003513 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3514 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003515 if (err < 0)
3516 goto failed;
3517
Marcel Holtmannf6b77122015-03-14 19:28:05 -07003518 err = mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev,
3519 data, len, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003520
Johan Hedbergb5235a62012-02-21 14:32:24 +02003521 goto failed;
3522 }
3523
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003524 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003525 if (!cmd) {
3526 err = -ENOMEM;
3527 goto failed;
3528 }
3529
Johan Hedberg13928972013-03-15 17:07:00 -05003530 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3531
Johan Hedberg890ea892013-03-15 17:06:52 -05003532 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003533
3534 if (lmp_bredr_capable(hdev)) {
3535 update_name(&req);
3536 update_eir(&req);
3537 }
3538
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003539 /* The name is stored in the scan response data and so
3540 * no need to udpate the advertising data here.
3541 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003542 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003543 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003544
Johan Hedberg13928972013-03-15 17:07:00 -05003545 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003546 if (err < 0)
3547 mgmt_pending_remove(cmd);
3548
3549failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003550 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003551 return err;
3552}
3553
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003554static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003555 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003556{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003557 struct mgmt_pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01003558 int err;
3559
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003560 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003561
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003562 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003563
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003564 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003565 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3566 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003567 goto unlock;
3568 }
3569
Andre Guedes9a1a1992012-07-24 15:03:48 -03003570 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003571 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3572 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003573 goto unlock;
3574 }
3575
Johan Hedberg333ae952015-03-17 13:48:47 +02003576 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003577 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3578 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003579 goto unlock;
3580 }
3581
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003582 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003583 if (!cmd) {
3584 err = -ENOMEM;
3585 goto unlock;
3586 }
3587
Johan Hedberg710f11c2014-05-26 11:21:22 +03003588 if (bredr_sc_enabled(hdev))
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003589 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
3590 0, NULL);
3591 else
3592 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3593
Szymon Jancc35938b2011-03-22 13:12:21 +01003594 if (err < 0)
3595 mgmt_pending_remove(cmd);
3596
3597unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003598 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003599 return err;
3600}
3601
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003602static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003603 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003604{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003605 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003606 int err;
3607
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003608 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003609
Johan Hedberg5d57e792015-01-23 10:10:38 +02003610 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003611 return mgmt_cmd_complete(sk, hdev->id,
3612 MGMT_OP_ADD_REMOTE_OOB_DATA,
3613 MGMT_STATUS_INVALID_PARAMS,
3614 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003615
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003616 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003617
Marcel Holtmannec109112014-01-10 02:07:30 -08003618 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3619 struct mgmt_cp_add_remote_oob_data *cp = data;
3620 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003621
Johan Hedbergc19a4952014-11-17 20:52:19 +02003622 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003623 err = mgmt_cmd_complete(sk, hdev->id,
3624 MGMT_OP_ADD_REMOTE_OOB_DATA,
3625 MGMT_STATUS_INVALID_PARAMS,
3626 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003627 goto unlock;
3628 }
3629
Marcel Holtmannec109112014-01-10 02:07:30 -08003630 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003631 cp->addr.type, cp->hash,
3632 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003633 if (err < 0)
3634 status = MGMT_STATUS_FAILED;
3635 else
3636 status = MGMT_STATUS_SUCCESS;
3637
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003638 err = mgmt_cmd_complete(sk, hdev->id,
3639 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3640 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003641 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3642 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003643 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003644 u8 status;
3645
Johan Hedberg86df9202014-10-26 20:52:27 +01003646 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003647 /* Enforce zero-valued 192-bit parameters as
3648 * long as legacy SMP OOB isn't implemented.
3649 */
3650 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3651 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003652 err = mgmt_cmd_complete(sk, hdev->id,
3653 MGMT_OP_ADD_REMOTE_OOB_DATA,
3654 MGMT_STATUS_INVALID_PARAMS,
3655 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003656 goto unlock;
3657 }
3658
Johan Hedberg86df9202014-10-26 20:52:27 +01003659 rand192 = NULL;
3660 hash192 = NULL;
3661 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003662 /* In case one of the P-192 values is set to zero,
3663 * then just disable OOB data for P-192.
3664 */
3665 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3666 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3667 rand192 = NULL;
3668 hash192 = NULL;
3669 } else {
3670 rand192 = cp->rand192;
3671 hash192 = cp->hash192;
3672 }
3673 }
3674
3675 /* In case one of the P-256 values is set to zero, then just
3676 * disable OOB data for P-256.
3677 */
3678 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3679 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3680 rand256 = NULL;
3681 hash256 = NULL;
3682 } else {
3683 rand256 = cp->rand256;
3684 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003685 }
3686
Johan Hedberg81328d5c2014-10-26 20:33:47 +01003687 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003688 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003689 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003690 if (err < 0)
3691 status = MGMT_STATUS_FAILED;
3692 else
3693 status = MGMT_STATUS_SUCCESS;
3694
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003695 err = mgmt_cmd_complete(sk, hdev->id,
3696 MGMT_OP_ADD_REMOTE_OOB_DATA,
3697 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003698 } else {
3699 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003700 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3701 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003702 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003703
Johan Hedbergc19a4952014-11-17 20:52:19 +02003704unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003705 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003706 return err;
3707}
3708
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003709static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003710 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003711{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003712 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003713 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003714 int err;
3715
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003716 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003717
Johan Hedbergc19a4952014-11-17 20:52:19 +02003718 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003719 return mgmt_cmd_complete(sk, hdev->id,
3720 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3721 MGMT_STATUS_INVALID_PARAMS,
3722 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003723
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003724 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003725
Johan Hedbergeedbd582014-11-15 09:34:23 +02003726 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3727 hci_remote_oob_data_clear(hdev);
3728 status = MGMT_STATUS_SUCCESS;
3729 goto done;
3730 }
3731
Johan Hedberg6928a922014-10-26 20:46:09 +01003732 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003733 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003734 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003735 else
Szymon Janca6785be2012-12-13 15:11:21 +01003736 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003737
Johan Hedbergeedbd582014-11-15 09:34:23 +02003738done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003739 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3740 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003741
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003742 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003743 return err;
3744}
3745
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003746static bool trigger_bredr_inquiry(struct hci_request *req, u8 *status)
3747{
3748 struct hci_dev *hdev = req->hdev;
3749 struct hci_cp_inquiry cp;
3750 /* General inquiry access code (GIAC) */
3751 u8 lap[3] = { 0x33, 0x8b, 0x9e };
3752
3753 *status = mgmt_bredr_support(hdev);
3754 if (*status)
3755 return false;
3756
3757 if (hci_dev_test_flag(hdev, HCI_INQUIRY)) {
3758 *status = MGMT_STATUS_BUSY;
3759 return false;
3760 }
3761
3762 hci_inquiry_cache_flush(hdev);
3763
3764 memset(&cp, 0, sizeof(cp));
3765 memcpy(&cp.lap, lap, sizeof(cp.lap));
3766 cp.length = DISCOV_BREDR_INQUIRY_LEN;
3767
3768 hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp);
3769
3770 return true;
3771}
3772
3773static bool trigger_le_scan(struct hci_request *req, u16 interval, u8 *status)
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003774{
Marcel Holtmann80190442014-12-04 11:36:36 +01003775 struct hci_dev *hdev = req->hdev;
3776 struct hci_cp_le_set_scan_param param_cp;
3777 struct hci_cp_le_set_scan_enable enable_cp;
Marcel Holtmann80190442014-12-04 11:36:36 +01003778 u8 own_addr_type;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003779 int err;
3780
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003781 *status = mgmt_le_support(hdev);
3782 if (*status)
3783 return false;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003784
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003785 if (hci_dev_test_flag(hdev, HCI_LE_ADV)) {
3786 /* Don't let discovery abort an outgoing connection attempt
3787 * that's using directed advertising.
3788 */
3789 if (hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT)) {
3790 *status = MGMT_STATUS_REJECTED;
Marcel Holtmann80190442014-12-04 11:36:36 +01003791 return false;
3792 }
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003793
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003794 disable_advertising(req);
3795 }
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003796
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003797 /* If controller is scanning, it means the background scanning is
3798 * running. Thus, we should temporarily stop it in order to set the
3799 * discovery scanning parameters.
3800 */
3801 if (hci_dev_test_flag(hdev, HCI_LE_SCAN))
3802 hci_req_add_le_scan_disable(req);
3803
3804 /* All active scans will be done with either a resolvable private
3805 * address (when privacy feature has been enabled) or non-resolvable
3806 * private address.
3807 */
3808 err = hci_update_random_address(req, true, &own_addr_type);
3809 if (err < 0) {
3810 *status = MGMT_STATUS_FAILED;
3811 return false;
3812 }
3813
3814 memset(&param_cp, 0, sizeof(param_cp));
3815 param_cp.type = LE_SCAN_ACTIVE;
3816 param_cp.interval = cpu_to_le16(interval);
3817 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
3818 param_cp.own_address_type = own_addr_type;
3819
3820 hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3821 &param_cp);
3822
3823 memset(&enable_cp, 0, sizeof(enable_cp));
3824 enable_cp.enable = LE_SCAN_ENABLE;
3825 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3826
3827 hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3828 &enable_cp);
3829
3830 return true;
3831}
3832
3833static bool trigger_discovery(struct hci_request *req, u8 *status)
3834{
3835 struct hci_dev *hdev = req->hdev;
3836
3837 switch (hdev->discovery.type) {
3838 case DISCOV_TYPE_BREDR:
3839 if (!trigger_bredr_inquiry(req, status))
3840 return false;
Marcel Holtmann80190442014-12-04 11:36:36 +01003841 break;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003842
Marcel Holtmann80190442014-12-04 11:36:36 +01003843 case DISCOV_TYPE_INTERLEAVED:
Jakub Pawlowski07d23342015-03-17 09:04:14 -07003844 if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY,
3845 &hdev->quirks)) {
3846 /* During simultaneous discovery, we double LE scan
3847 * interval. We must leave some time for the controller
3848 * to do BR/EDR inquiry.
3849 */
3850 if (!trigger_le_scan(req, DISCOV_LE_SCAN_INT * 2,
3851 status))
3852 return false;
3853
3854 if (!trigger_bredr_inquiry(req, status))
3855 return false;
3856
3857 return true;
3858 }
3859
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003860 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmann80190442014-12-04 11:36:36 +01003861 *status = MGMT_STATUS_NOT_SUPPORTED;
3862 return false;
3863 }
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003864 /* fall through */
Marcel Holtmann80190442014-12-04 11:36:36 +01003865
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003866 case DISCOV_TYPE_LE:
3867 if (!trigger_le_scan(req, DISCOV_LE_SCAN_INT, status))
Marcel Holtmann80190442014-12-04 11:36:36 +01003868 return false;
Marcel Holtmann80190442014-12-04 11:36:36 +01003869 break;
3870
3871 default:
3872 *status = MGMT_STATUS_INVALID_PARAMS;
3873 return false;
3874 }
3875
3876 return true;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003877}
3878
Marcel Holtmann1904a852015-01-11 13:50:44 -08003879static void start_discovery_complete(struct hci_dev *hdev, u8 status,
3880 u16 opcode)
Andre Guedes7c307722013-04-30 15:29:28 -03003881{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003882 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003883 unsigned long timeout;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003884
Andre Guedes7c307722013-04-30 15:29:28 -03003885 BT_DBG("status %d", status);
3886
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003887 hci_dev_lock(hdev);
3888
Johan Hedberg333ae952015-03-17 13:48:47 +02003889 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003890 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02003891 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003892
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003893 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003894 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003895 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003896 }
3897
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003898 if (status) {
3899 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3900 goto unlock;
3901 }
3902
Andre Guedes7c307722013-04-30 15:29:28 -03003903 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
Andre Guedes7c307722013-04-30 15:29:28 -03003904
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08003905 /* If the scan involves LE scan, pick proper timeout to schedule
3906 * hdev->le_scan_disable that will stop it.
3907 */
Andre Guedes7c307722013-04-30 15:29:28 -03003908 switch (hdev->discovery.type) {
3909 case DISCOV_TYPE_LE:
Lukasz Rymanowski3d5a76f2014-03-27 20:55:21 +01003910 timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003911 break;
Andre Guedes7c307722013-04-30 15:29:28 -03003912 case DISCOV_TYPE_INTERLEAVED:
Jakub Pawlowski07d23342015-03-17 09:04:14 -07003913 /* When running simultaneous discovery, the LE scanning time
3914 * should occupy the whole discovery time sine BR/EDR inquiry
3915 * and LE scanning are scheduled by the controller.
3916 *
3917 * For interleaving discovery in comparison, BR/EDR inquiry
3918 * and LE scanning are done sequentially with separate
3919 * timeouts.
3920 */
3921 if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks))
3922 timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
3923 else
3924 timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
Andre Guedes7c307722013-04-30 15:29:28 -03003925 break;
Andre Guedes7c307722013-04-30 15:29:28 -03003926 case DISCOV_TYPE_BREDR:
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003927 timeout = 0;
Andre Guedes7c307722013-04-30 15:29:28 -03003928 break;
Andre Guedes7c307722013-04-30 15:29:28 -03003929 default:
3930 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003931 timeout = 0;
3932 break;
Andre Guedes7c307722013-04-30 15:29:28 -03003933 }
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003934
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08003935 if (timeout) {
3936 /* When service discovery is used and the controller has
3937 * a strict duplicate filter, it is important to remember
3938 * the start and duration of the scan. This is required
3939 * for restarting scanning during the discovery phase.
3940 */
3941 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER,
3942 &hdev->quirks) &&
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08003943 hdev->discovery.result_filtering) {
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08003944 hdev->discovery.scan_start = jiffies;
3945 hdev->discovery.scan_duration = timeout;
3946 }
3947
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003948 queue_delayed_work(hdev->workqueue,
3949 &hdev->le_scan_disable, timeout);
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08003950 }
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003951
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003952unlock:
3953 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003954}
3955
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003956static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003957 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003958{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003959 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003960 struct mgmt_pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003961 struct hci_request req;
Marcel Holtmann80190442014-12-04 11:36:36 +01003962 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003963 int err;
3964
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003965 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003966
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003967 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003968
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003969 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003970 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3971 MGMT_STATUS_NOT_POWERED,
3972 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003973 goto failed;
3974 }
3975
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01003976 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003977 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003978 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3979 MGMT_STATUS_BUSY, &cp->type,
3980 sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03003981 goto failed;
3982 }
3983
Johan Hedberg2922a942014-12-05 13:36:06 +02003984 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04003985 if (!cmd) {
3986 err = -ENOMEM;
3987 goto failed;
3988 }
3989
Johan Hedberg2922a942014-12-05 13:36:06 +02003990 cmd->cmd_complete = generic_cmd_complete;
3991
Marcel Holtmann22078802014-12-05 11:45:22 +01003992 /* Clear the discovery filter first to free any previously
3993 * allocated memory for the UUID list.
3994 */
3995 hci_discovery_filter_clear(hdev);
3996
Andre Guedes4aab14e2012-02-17 20:39:36 -03003997 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01003998 hdev->discovery.report_invalid_rssi = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03003999
Andre Guedes7c307722013-04-30 15:29:28 -03004000 hci_req_init(&req, hdev);
4001
Marcel Holtmann80190442014-12-04 11:36:36 +01004002 if (!trigger_discovery(&req, &status)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004003 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4004 status, &cp->type, sizeof(cp->type));
Johan Hedberg04106752013-01-10 14:54:09 +02004005 mgmt_pending_remove(cmd);
4006 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004007 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004008
Andre Guedes7c307722013-04-30 15:29:28 -03004009 err = hci_req_run(&req, start_discovery_complete);
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004010 if (err < 0) {
Johan Hedberg14a53662011-04-27 10:29:56 -04004011 mgmt_pending_remove(cmd);
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004012 goto failed;
4013 }
4014
4015 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04004016
4017failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004018 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004019 return err;
4020}
4021
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004022static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4023 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004024{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004025 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4026 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004027}
4028
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004029static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4030 void *data, u16 len)
4031{
4032 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004033 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004034 struct hci_request req;
4035 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4036 u16 uuid_count, expected_len;
4037 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004038 int err;
4039
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004040 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004041
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004042 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004043
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004044 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004045 err = mgmt_cmd_complete(sk, hdev->id,
4046 MGMT_OP_START_SERVICE_DISCOVERY,
4047 MGMT_STATUS_NOT_POWERED,
4048 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004049 goto failed;
4050 }
4051
4052 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004053 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004054 err = mgmt_cmd_complete(sk, hdev->id,
4055 MGMT_OP_START_SERVICE_DISCOVERY,
4056 MGMT_STATUS_BUSY, &cp->type,
4057 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004058 goto failed;
4059 }
4060
4061 uuid_count = __le16_to_cpu(cp->uuid_count);
4062 if (uuid_count > max_uuid_count) {
4063 BT_ERR("service_discovery: too big uuid_count value %u",
4064 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004065 err = mgmt_cmd_complete(sk, hdev->id,
4066 MGMT_OP_START_SERVICE_DISCOVERY,
4067 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4068 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004069 goto failed;
4070 }
4071
4072 expected_len = sizeof(*cp) + uuid_count * 16;
4073 if (expected_len != len) {
4074 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
4075 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004076 err = mgmt_cmd_complete(sk, hdev->id,
4077 MGMT_OP_START_SERVICE_DISCOVERY,
4078 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4079 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004080 goto failed;
4081 }
4082
4083 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02004084 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004085 if (!cmd) {
4086 err = -ENOMEM;
4087 goto failed;
4088 }
4089
Johan Hedberg2922a942014-12-05 13:36:06 +02004090 cmd->cmd_complete = service_discovery_cmd_complete;
4091
Marcel Holtmann22078802014-12-05 11:45:22 +01004092 /* Clear the discovery filter first to free any previously
4093 * allocated memory for the UUID list.
4094 */
4095 hci_discovery_filter_clear(hdev);
4096
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004097 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004098 hdev->discovery.type = cp->type;
4099 hdev->discovery.rssi = cp->rssi;
4100 hdev->discovery.uuid_count = uuid_count;
4101
4102 if (uuid_count > 0) {
4103 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4104 GFP_KERNEL);
4105 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004106 err = mgmt_cmd_complete(sk, hdev->id,
4107 MGMT_OP_START_SERVICE_DISCOVERY,
4108 MGMT_STATUS_FAILED,
4109 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004110 mgmt_pending_remove(cmd);
4111 goto failed;
4112 }
4113 }
4114
4115 hci_req_init(&req, hdev);
4116
4117 if (!trigger_discovery(&req, &status)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004118 err = mgmt_cmd_complete(sk, hdev->id,
4119 MGMT_OP_START_SERVICE_DISCOVERY,
4120 status, &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004121 mgmt_pending_remove(cmd);
4122 goto failed;
4123 }
4124
4125 err = hci_req_run(&req, start_discovery_complete);
4126 if (err < 0) {
4127 mgmt_pending_remove(cmd);
4128 goto failed;
4129 }
4130
4131 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
4132
4133failed:
4134 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004135 return err;
4136}
4137
Marcel Holtmann1904a852015-01-11 13:50:44 -08004138static void stop_discovery_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004139{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004140 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004141
Andre Guedes0e05bba2013-04-30 15:29:33 -03004142 BT_DBG("status %d", status);
4143
4144 hci_dev_lock(hdev);
4145
Johan Hedberg333ae952015-03-17 13:48:47 +02004146 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004147 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004148 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004149 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004150 }
4151
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004152 if (!status)
4153 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004154
Andre Guedes0e05bba2013-04-30 15:29:33 -03004155 hci_dev_unlock(hdev);
4156}
4157
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004158static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004159 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004160{
Johan Hedbergd9306502012-02-20 23:25:18 +02004161 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004162 struct mgmt_pending_cmd *cmd;
Andre Guedes0e05bba2013-04-30 15:29:33 -03004163 struct hci_request req;
Johan Hedberg14a53662011-04-27 10:29:56 -04004164 int err;
4165
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004166 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004167
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004168 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004169
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004170 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004171 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4172 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4173 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004174 goto unlock;
4175 }
4176
4177 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004178 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4179 MGMT_STATUS_INVALID_PARAMS,
4180 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004181 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004182 }
4183
Johan Hedberg2922a942014-12-05 13:36:06 +02004184 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004185 if (!cmd) {
4186 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004187 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004188 }
4189
Johan Hedberg2922a942014-12-05 13:36:06 +02004190 cmd->cmd_complete = generic_cmd_complete;
4191
Andre Guedes0e05bba2013-04-30 15:29:33 -03004192 hci_req_init(&req, hdev);
4193
Johan Hedberg21a60d32014-06-10 14:05:58 +03004194 hci_stop_discovery(&req);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004195
Johan Hedberg21a60d32014-06-10 14:05:58 +03004196 err = hci_req_run(&req, stop_discovery_complete);
4197 if (!err) {
4198 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004199 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004200 }
4201
Johan Hedberg21a60d32014-06-10 14:05:58 +03004202 mgmt_pending_remove(cmd);
4203
4204 /* If no HCI commands were sent we're done */
4205 if (err == -ENODATA) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004206 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
4207 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg21a60d32014-06-10 14:05:58 +03004208 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
4209 }
Johan Hedberg14a53662011-04-27 10:29:56 -04004210
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004211unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004212 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004213 return err;
4214}
4215
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004216static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004217 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004218{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004219 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004220 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004221 int err;
4222
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004223 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004224
Johan Hedberg561aafb2012-01-04 13:31:59 +02004225 hci_dev_lock(hdev);
4226
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004227 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004228 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4229 MGMT_STATUS_FAILED, &cp->addr,
4230 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004231 goto failed;
4232 }
4233
Johan Hedberga198e7b2012-02-17 14:27:06 +02004234 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004235 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004236 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4237 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4238 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004239 goto failed;
4240 }
4241
4242 if (cp->name_known) {
4243 e->name_state = NAME_KNOWN;
4244 list_del(&e->list);
4245 } else {
4246 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02004247 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004248 }
4249
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004250 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4251 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004252
4253failed:
4254 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004255 return err;
4256}
4257
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004258static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004259 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004260{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004261 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004262 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004263 int err;
4264
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004265 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004266
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004267 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004268 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4269 MGMT_STATUS_INVALID_PARAMS,
4270 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004271
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004272 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004273
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004274 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4275 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004276 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004277 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004278 goto done;
4279 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004280
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004281 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4282 sk);
4283 status = MGMT_STATUS_SUCCESS;
4284
4285done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004286 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4287 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004288
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004289 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004290
4291 return err;
4292}
4293
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004294static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004295 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004296{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004297 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004298 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004299 int err;
4300
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004301 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004302
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004303 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004304 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4305 MGMT_STATUS_INVALID_PARAMS,
4306 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004307
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004308 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004309
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004310 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4311 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004312 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004313 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004314 goto done;
4315 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004316
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004317 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4318 sk);
4319 status = MGMT_STATUS_SUCCESS;
4320
4321done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004322 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4323 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004324
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004325 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004326
4327 return err;
4328}
4329
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004330static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4331 u16 len)
4332{
4333 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004334 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004335 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004336 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004337
4338 BT_DBG("%s", hdev->name);
4339
Szymon Jancc72d4b82012-03-16 16:02:57 +01004340 source = __le16_to_cpu(cp->source);
4341
4342 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004343 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4344 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004345
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004346 hci_dev_lock(hdev);
4347
Szymon Jancc72d4b82012-03-16 16:02:57 +01004348 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004349 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4350 hdev->devid_product = __le16_to_cpu(cp->product);
4351 hdev->devid_version = __le16_to_cpu(cp->version);
4352
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004353 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4354 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004355
Johan Hedberg890ea892013-03-15 17:06:52 -05004356 hci_req_init(&req, hdev);
4357 update_eir(&req);
4358 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004359
4360 hci_dev_unlock(hdev);
4361
4362 return err;
4363}
4364
Marcel Holtmann1904a852015-01-11 13:50:44 -08004365static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4366 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004367{
4368 struct cmd_lookup match = { NULL, hdev };
4369
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304370 hci_dev_lock(hdev);
4371
Johan Hedberg4375f102013-09-25 13:26:10 +03004372 if (status) {
4373 u8 mgmt_err = mgmt_status(status);
4374
4375 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4376 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304377 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004378 }
4379
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004380 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004381 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004382 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004383 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004384
Johan Hedberg4375f102013-09-25 13:26:10 +03004385 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4386 &match);
4387
4388 new_settings(hdev, match.sk);
4389
4390 if (match.sk)
4391 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304392
4393unlock:
4394 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004395}
4396
Marcel Holtmann21b51872013-10-10 09:47:53 -07004397static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4398 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004399{
4400 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004401 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004402 struct hci_request req;
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004403 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004404 int err;
4405
4406 BT_DBG("request for %s", hdev->name);
4407
Johan Hedberge6fe7982013-10-02 15:45:22 +03004408 status = mgmt_le_support(hdev);
4409 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004410 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4411 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004412
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004413 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004414 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4415 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004416
4417 hci_dev_lock(hdev);
4418
4419 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004420
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004421 /* The following conditions are ones which mean that we should
4422 * not do any HCI communication but directly send a mgmt
4423 * response to user space (after toggling the flag if
4424 * necessary).
4425 */
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004426 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004427 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4428 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004429 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004430 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004431 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004432 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004433
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004434 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004435 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004436 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004437 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004438 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004439 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004440 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004441 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004442 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004443 }
4444
4445 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4446 if (err < 0)
4447 goto unlock;
4448
4449 if (changed)
4450 err = new_settings(hdev, sk);
4451
4452 goto unlock;
4453 }
4454
Johan Hedberg333ae952015-03-17 13:48:47 +02004455 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4456 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004457 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4458 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004459 goto unlock;
4460 }
4461
4462 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4463 if (!cmd) {
4464 err = -ENOMEM;
4465 goto unlock;
4466 }
4467
4468 hci_req_init(&req, hdev);
4469
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004470 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004471 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004472 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004473 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb042015-03-12 22:30:58 -07004474
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004475 if (val)
4476 enable_advertising(&req);
4477 else
4478 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03004479
4480 err = hci_req_run(&req, set_advertising_complete);
4481 if (err < 0)
4482 mgmt_pending_remove(cmd);
4483
4484unlock:
4485 hci_dev_unlock(hdev);
4486 return err;
4487}
4488
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004489static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4490 void *data, u16 len)
4491{
4492 struct mgmt_cp_set_static_address *cp = data;
4493 int err;
4494
4495 BT_DBG("%s", hdev->name);
4496
Marcel Holtmann62af4442013-10-02 22:10:32 -07004497 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004498 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4499 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004500
4501 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004502 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4503 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004504
4505 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4506 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004507 return mgmt_cmd_status(sk, hdev->id,
4508 MGMT_OP_SET_STATIC_ADDRESS,
4509 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004510
4511 /* Two most significant bits shall be set */
4512 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004513 return mgmt_cmd_status(sk, hdev->id,
4514 MGMT_OP_SET_STATIC_ADDRESS,
4515 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004516 }
4517
4518 hci_dev_lock(hdev);
4519
4520 bacpy(&hdev->static_addr, &cp->bdaddr);
4521
Marcel Holtmann93690c22015-03-06 10:11:21 -08004522 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4523 if (err < 0)
4524 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004525
Marcel Holtmann93690c22015-03-06 10:11:21 -08004526 err = new_settings(hdev, sk);
4527
4528unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004529 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004530 return err;
4531}
4532
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004533static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4534 void *data, u16 len)
4535{
4536 struct mgmt_cp_set_scan_params *cp = data;
4537 __u16 interval, window;
4538 int err;
4539
4540 BT_DBG("%s", hdev->name);
4541
4542 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004543 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4544 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004545
4546 interval = __le16_to_cpu(cp->interval);
4547
4548 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004549 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4550 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004551
4552 window = __le16_to_cpu(cp->window);
4553
4554 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004555 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4556 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004557
Marcel Holtmann899e1072013-10-14 09:55:32 -07004558 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004559 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4560 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004561
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004562 hci_dev_lock(hdev);
4563
4564 hdev->le_scan_interval = interval;
4565 hdev->le_scan_window = window;
4566
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004567 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4568 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004569
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004570 /* If background scan is running, restart it so new parameters are
4571 * loaded.
4572 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004573 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004574 hdev->discovery.state == DISCOVERY_STOPPED) {
4575 struct hci_request req;
4576
4577 hci_req_init(&req, hdev);
4578
4579 hci_req_add_le_scan_disable(&req);
4580 hci_req_add_le_passive_scan(&req);
4581
4582 hci_req_run(&req, NULL);
4583 }
4584
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004585 hci_dev_unlock(hdev);
4586
4587 return err;
4588}
4589
Marcel Holtmann1904a852015-01-11 13:50:44 -08004590static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4591 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004592{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004593 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004594
4595 BT_DBG("status 0x%02x", status);
4596
4597 hci_dev_lock(hdev);
4598
Johan Hedberg333ae952015-03-17 13:48:47 +02004599 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004600 if (!cmd)
4601 goto unlock;
4602
4603 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004604 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4605 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004606 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004607 struct mgmt_mode *cp = cmd->param;
4608
4609 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004610 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004611 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004612 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004613
Johan Hedberg33e38b32013-03-15 17:07:05 -05004614 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4615 new_settings(hdev, cmd->sk);
4616 }
4617
4618 mgmt_pending_remove(cmd);
4619
4620unlock:
4621 hci_dev_unlock(hdev);
4622}
4623
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004624static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004625 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004626{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004627 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004628 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004629 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004630 int err;
4631
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004632 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004633
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004634 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004635 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004636 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4637 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004638
Johan Hedberga7e80f22013-01-09 16:05:19 +02004639 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004640 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4641 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004642
Antti Julkuf6422ec2011-06-22 13:11:56 +03004643 hci_dev_lock(hdev);
4644
Johan Hedberg333ae952015-03-17 13:48:47 +02004645 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004646 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4647 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004648 goto unlock;
4649 }
4650
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004651 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004652 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4653 hdev);
4654 goto unlock;
4655 }
4656
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004657 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004658 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004659 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4660 hdev);
4661 new_settings(hdev, sk);
4662 goto unlock;
4663 }
4664
Johan Hedberg33e38b32013-03-15 17:07:05 -05004665 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4666 data, len);
4667 if (!cmd) {
4668 err = -ENOMEM;
4669 goto unlock;
4670 }
4671
4672 hci_req_init(&req, hdev);
4673
Johan Hedberg406d7802013-03-15 17:07:09 -05004674 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004675
4676 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004677 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004678 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4679 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004680 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004681 }
4682
Johan Hedberg33e38b32013-03-15 17:07:05 -05004683unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004684 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004685
Antti Julkuf6422ec2011-06-22 13:11:56 +03004686 return err;
4687}
4688
Marcel Holtmann1904a852015-01-11 13:50:44 -08004689static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004690{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004691 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004692
4693 BT_DBG("status 0x%02x", status);
4694
4695 hci_dev_lock(hdev);
4696
Johan Hedberg333ae952015-03-17 13:48:47 +02004697 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004698 if (!cmd)
4699 goto unlock;
4700
4701 if (status) {
4702 u8 mgmt_err = mgmt_status(status);
4703
4704 /* We need to restore the flag if related HCI commands
4705 * failed.
4706 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004707 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004708
Johan Hedberga69e8372015-03-06 21:08:53 +02004709 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004710 } else {
4711 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4712 new_settings(hdev, cmd->sk);
4713 }
4714
4715 mgmt_pending_remove(cmd);
4716
4717unlock:
4718 hci_dev_unlock(hdev);
4719}
4720
4721static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4722{
4723 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004724 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004725 struct hci_request req;
4726 int err;
4727
4728 BT_DBG("request for %s", hdev->name);
4729
4730 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004731 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4732 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004733
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004734 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004735 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4736 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004737
4738 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004739 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4740 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004741
4742 hci_dev_lock(hdev);
4743
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004744 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004745 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4746 goto unlock;
4747 }
4748
4749 if (!hdev_is_powered(hdev)) {
4750 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004751 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4752 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4753 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4754 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4755 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004756 }
4757
Marcel Holtmannce05d602015-03-13 02:11:03 -07004758 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004759
4760 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4761 if (err < 0)
4762 goto unlock;
4763
4764 err = new_settings(hdev, sk);
4765 goto unlock;
4766 }
4767
4768 /* Reject disabling when powered on */
4769 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004770 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4771 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004772 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004773 } else {
4774 /* When configuring a dual-mode controller to operate
4775 * with LE only and using a static address, then switching
4776 * BR/EDR back on is not allowed.
4777 *
4778 * Dual-mode controllers shall operate with the public
4779 * address as its identity address for BR/EDR and LE. So
4780 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004781 *
4782 * The same restrictions applies when secure connections
4783 * has been enabled. For BR/EDR this is a controller feature
4784 * while for LE it is a host stack feature. This means that
4785 * switching BR/EDR back on when secure connections has been
4786 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004787 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004788 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004789 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004790 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004791 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4792 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004793 goto unlock;
4794 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004795 }
4796
Johan Hedberg333ae952015-03-17 13:48:47 +02004797 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004798 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4799 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004800 goto unlock;
4801 }
4802
4803 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4804 if (!cmd) {
4805 err = -ENOMEM;
4806 goto unlock;
4807 }
4808
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004809 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03004810 * generates the correct flags.
4811 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004812 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004813
4814 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004815
Johan Hedberg432df052014-08-01 11:13:31 +03004816 write_fast_connectable(&req, false);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02004817 __hci_update_page_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004818
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004819 /* Since only the advertising data flags will change, there
4820 * is no need to update the scan response data.
4821 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004822 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004823
Johan Hedberg0663ca22013-10-02 13:43:14 +03004824 err = hci_req_run(&req, set_bredr_complete);
4825 if (err < 0)
4826 mgmt_pending_remove(cmd);
4827
4828unlock:
4829 hci_dev_unlock(hdev);
4830 return err;
4831}
4832
Johan Hedberga1443f52015-01-23 15:42:46 +02004833static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4834{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004835 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004836 struct mgmt_mode *cp;
4837
4838 BT_DBG("%s status %u", hdev->name, status);
4839
4840 hci_dev_lock(hdev);
4841
Johan Hedberg333ae952015-03-17 13:48:47 +02004842 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02004843 if (!cmd)
4844 goto unlock;
4845
4846 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004847 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4848 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004849 goto remove;
4850 }
4851
4852 cp = cmd->param;
4853
4854 switch (cp->val) {
4855 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004856 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4857 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004858 break;
4859 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004860 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004861 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004862 break;
4863 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004864 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4865 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004866 break;
4867 }
4868
4869 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4870 new_settings(hdev, cmd->sk);
4871
4872remove:
4873 mgmt_pending_remove(cmd);
4874unlock:
4875 hci_dev_unlock(hdev);
4876}
4877
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004878static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4879 void *data, u16 len)
4880{
4881 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004882 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004883 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004884 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004885 int err;
4886
4887 BT_DBG("request for %s", hdev->name);
4888
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004889 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004890 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004891 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4892 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004893
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004894 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004895 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004896 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004897 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4898 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004899
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004900 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004901 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004902 MGMT_STATUS_INVALID_PARAMS);
4903
4904 hci_dev_lock(hdev);
4905
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004906 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004907 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004908 bool changed;
4909
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004910 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004911 changed = !hci_dev_test_and_set_flag(hdev,
4912 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004913 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004914 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004915 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004916 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004917 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004918 changed = hci_dev_test_and_clear_flag(hdev,
4919 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004920 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004921 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004922
4923 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4924 if (err < 0)
4925 goto failed;
4926
4927 if (changed)
4928 err = new_settings(hdev, sk);
4929
4930 goto failed;
4931 }
4932
Johan Hedberg333ae952015-03-17 13:48:47 +02004933 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004934 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4935 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004936 goto failed;
4937 }
4938
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004939 val = !!cp->val;
4940
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004941 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4942 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004943 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4944 goto failed;
4945 }
4946
4947 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4948 if (!cmd) {
4949 err = -ENOMEM;
4950 goto failed;
4951 }
4952
Johan Hedberga1443f52015-01-23 15:42:46 +02004953 hci_req_init(&req, hdev);
4954 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4955 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004956 if (err < 0) {
4957 mgmt_pending_remove(cmd);
4958 goto failed;
4959 }
4960
4961failed:
4962 hci_dev_unlock(hdev);
4963 return err;
4964}
4965
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004966static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4967 void *data, u16 len)
4968{
4969 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03004970 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004971 int err;
4972
4973 BT_DBG("request for %s", hdev->name);
4974
Johan Hedbergb97109792014-06-24 14:00:28 +03004975 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_DEBUG_KEYS,
4977 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004978
4979 hci_dev_lock(hdev);
4980
4981 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07004982 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004983 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004984 changed = hci_dev_test_and_clear_flag(hdev,
4985 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004986
Johan Hedbergb97109792014-06-24 14:00:28 +03004987 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07004988 use_changed = !hci_dev_test_and_set_flag(hdev,
4989 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004990 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004991 use_changed = hci_dev_test_and_clear_flag(hdev,
4992 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03004993
4994 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004995 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03004996 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
4997 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
4998 sizeof(mode), &mode);
4999 }
5000
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005001 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
5002 if (err < 0)
5003 goto unlock;
5004
5005 if (changed)
5006 err = new_settings(hdev, sk);
5007
5008unlock:
5009 hci_dev_unlock(hdev);
5010 return err;
5011}
5012
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005013static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5014 u16 len)
5015{
5016 struct mgmt_cp_set_privacy *cp = cp_data;
5017 bool changed;
5018 int err;
5019
5020 BT_DBG("request for %s", hdev->name);
5021
5022 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005023 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5024 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005025
5026 if (cp->privacy != 0x00 && cp->privacy != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005027 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5028 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005029
5030 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005031 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5032 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005033
5034 hci_dev_lock(hdev);
5035
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005036 /* If user space supports this command it is also expected to
5037 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
5038 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005039 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005040
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005041 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005042 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005043 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005044 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005045 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005046 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005047 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005048 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005049 }
5050
5051 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
5052 if (err < 0)
5053 goto unlock;
5054
5055 if (changed)
5056 err = new_settings(hdev, sk);
5057
5058unlock:
5059 hci_dev_unlock(hdev);
5060 return err;
5061}
5062
Johan Hedberg41edf162014-02-18 10:19:35 +02005063static bool irk_is_valid(struct mgmt_irk_info *irk)
5064{
5065 switch (irk->addr.type) {
5066 case BDADDR_LE_PUBLIC:
5067 return true;
5068
5069 case BDADDR_LE_RANDOM:
5070 /* Two most significant bits shall be set */
5071 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5072 return false;
5073 return true;
5074 }
5075
5076 return false;
5077}
5078
5079static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5080 u16 len)
5081{
5082 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005083 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5084 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005085 u16 irk_count, expected_len;
5086 int i, err;
5087
5088 BT_DBG("request for %s", hdev->name);
5089
5090 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005091 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5092 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005093
5094 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005095 if (irk_count > max_irk_count) {
5096 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005097 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5098 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005099 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005100
5101 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
5102 if (expected_len != len) {
5103 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02005104 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005105 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5106 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005107 }
5108
5109 BT_DBG("%s irk_count %u", hdev->name, irk_count);
5110
5111 for (i = 0; i < irk_count; i++) {
5112 struct mgmt_irk_info *key = &cp->irks[i];
5113
5114 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005115 return mgmt_cmd_status(sk, hdev->id,
5116 MGMT_OP_LOAD_IRKS,
5117 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005118 }
5119
5120 hci_dev_lock(hdev);
5121
5122 hci_smp_irks_clear(hdev);
5123
5124 for (i = 0; i < irk_count; i++) {
5125 struct mgmt_irk_info *irk = &cp->irks[i];
5126 u8 addr_type;
5127
5128 if (irk->addr.type == BDADDR_LE_PUBLIC)
5129 addr_type = ADDR_LE_DEV_PUBLIC;
5130 else
5131 addr_type = ADDR_LE_DEV_RANDOM;
5132
5133 hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
5134 BDADDR_ANY);
5135 }
5136
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005137 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005138
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005139 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005140
5141 hci_dev_unlock(hdev);
5142
5143 return err;
5144}
5145
Johan Hedberg3f706b72013-01-20 14:27:16 +02005146static bool ltk_is_valid(struct mgmt_ltk_info *key)
5147{
5148 if (key->master != 0x00 && key->master != 0x01)
5149 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005150
5151 switch (key->addr.type) {
5152 case BDADDR_LE_PUBLIC:
5153 return true;
5154
5155 case BDADDR_LE_RANDOM:
5156 /* Two most significant bits shall be set */
5157 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5158 return false;
5159 return true;
5160 }
5161
5162 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005163}
5164
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005165static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005166 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005167{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005168 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005169 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5170 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005171 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005172 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005173
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005174 BT_DBG("request for %s", hdev->name);
5175
5176 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005177 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5178 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005179
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005180 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005181 if (key_count > max_key_count) {
5182 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005183 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5184 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005185 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005186
5187 expected_len = sizeof(*cp) + key_count *
5188 sizeof(struct mgmt_ltk_info);
5189 if (expected_len != len) {
5190 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02005191 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005192 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5193 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005194 }
5195
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005196 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005197
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005198 for (i = 0; i < key_count; i++) {
5199 struct mgmt_ltk_info *key = &cp->keys[i];
5200
Johan Hedberg3f706b72013-01-20 14:27:16 +02005201 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005202 return mgmt_cmd_status(sk, hdev->id,
5203 MGMT_OP_LOAD_LONG_TERM_KEYS,
5204 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005205 }
5206
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005207 hci_dev_lock(hdev);
5208
5209 hci_smp_ltks_clear(hdev);
5210
5211 for (i = 0; i < key_count; i++) {
5212 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedbergd7b25452014-05-23 13:19:53 +03005213 u8 type, addr_type, authenticated;
Marcel Holtmann79d95a12013-10-13 03:57:38 -07005214
5215 if (key->addr.type == BDADDR_LE_PUBLIC)
5216 addr_type = ADDR_LE_DEV_PUBLIC;
5217 else
5218 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005219
Johan Hedberg61b43352014-05-29 19:36:53 +03005220 switch (key->type) {
5221 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005222 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005223 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005224 break;
5225 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005226 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005227 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005228 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005229 case MGMT_LTK_P256_UNAUTH:
5230 authenticated = 0x00;
5231 type = SMP_LTK_P256;
5232 break;
5233 case MGMT_LTK_P256_AUTH:
5234 authenticated = 0x01;
5235 type = SMP_LTK_P256;
5236 break;
5237 case MGMT_LTK_P256_DEBUG:
5238 authenticated = 0x00;
5239 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03005240 default:
5241 continue;
5242 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005243
Johan Hedberg35d70272014-02-19 14:57:47 +02005244 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type,
Johan Hedbergd7b25452014-05-23 13:19:53 +03005245 authenticated, key->val, key->enc_size, key->ediv,
Johan Hedberg35d70272014-02-19 14:57:47 +02005246 key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005247 }
5248
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005249 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005250 NULL, 0);
5251
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005252 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005253
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005254 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005255}
5256
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005257static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005258{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005259 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005260 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005261 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005262
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005263 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005264
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005265 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005266 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005267 rp.tx_power = conn->tx_power;
5268 rp.max_tx_power = conn->max_tx_power;
5269 } else {
5270 rp.rssi = HCI_RSSI_INVALID;
5271 rp.tx_power = HCI_TX_POWER_INVALID;
5272 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005273 }
5274
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005275 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5276 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005277
5278 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005279 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005280
5281 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005282}
5283
Marcel Holtmann1904a852015-01-11 13:50:44 -08005284static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5285 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005286{
5287 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005288 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005289 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005290 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005291 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005292
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005293 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005294
5295 hci_dev_lock(hdev);
5296
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005297 /* Commands sent in request are either Read RSSI or Read Transmit Power
5298 * Level so we check which one was last sent to retrieve connection
5299 * handle. Both commands have handle as first parameter so it's safe to
5300 * cast data on the same command struct.
5301 *
5302 * First command sent is always Read RSSI and we fail only if it fails.
5303 * In other case we simply override error to indicate success as we
5304 * already remembered if TX power value is actually valid.
5305 */
5306 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5307 if (!cp) {
5308 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005309 status = MGMT_STATUS_SUCCESS;
5310 } else {
5311 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005312 }
5313
5314 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005315 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005316 goto unlock;
5317 }
5318
5319 handle = __le16_to_cpu(cp->handle);
5320 conn = hci_conn_hash_lookup_handle(hdev, handle);
5321 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005322 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005323 goto unlock;
5324 }
5325
Johan Hedberg333ae952015-03-17 13:48:47 +02005326 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005327 if (!cmd)
5328 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005329
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005330 cmd->cmd_complete(cmd, status);
5331 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005332
5333unlock:
5334 hci_dev_unlock(hdev);
5335}
5336
5337static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5338 u16 len)
5339{
5340 struct mgmt_cp_get_conn_info *cp = data;
5341 struct mgmt_rp_get_conn_info rp;
5342 struct hci_conn *conn;
5343 unsigned long conn_info_age;
5344 int err = 0;
5345
5346 BT_DBG("%s", hdev->name);
5347
5348 memset(&rp, 0, sizeof(rp));
5349 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5350 rp.addr.type = cp->addr.type;
5351
5352 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005353 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5354 MGMT_STATUS_INVALID_PARAMS,
5355 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005356
5357 hci_dev_lock(hdev);
5358
5359 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005360 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5361 MGMT_STATUS_NOT_POWERED, &rp,
5362 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005363 goto unlock;
5364 }
5365
5366 if (cp->addr.type == BDADDR_BREDR)
5367 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5368 &cp->addr.bdaddr);
5369 else
5370 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5371
5372 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005373 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5374 MGMT_STATUS_NOT_CONNECTED, &rp,
5375 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005376 goto unlock;
5377 }
5378
Johan Hedberg333ae952015-03-17 13:48:47 +02005379 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005380 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5381 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005382 goto unlock;
5383 }
5384
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005385 /* To avoid client trying to guess when to poll again for information we
5386 * calculate conn info age as random value between min/max set in hdev.
5387 */
5388 conn_info_age = hdev->conn_info_min_age +
5389 prandom_u32_max(hdev->conn_info_max_age -
5390 hdev->conn_info_min_age);
5391
5392 /* Query controller to refresh cached values if they are too old or were
5393 * never read.
5394 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005395 if (time_after(jiffies, conn->conn_info_timestamp +
5396 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005397 !conn->conn_info_timestamp) {
5398 struct hci_request req;
5399 struct hci_cp_read_tx_power req_txp_cp;
5400 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005401 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005402
5403 hci_req_init(&req, hdev);
5404 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5405 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5406 &req_rssi_cp);
5407
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005408 /* For LE links TX power does not change thus we don't need to
5409 * query for it once value is known.
5410 */
5411 if (!bdaddr_type_is_le(cp->addr.type) ||
5412 conn->tx_power == HCI_TX_POWER_INVALID) {
5413 req_txp_cp.handle = cpu_to_le16(conn->handle);
5414 req_txp_cp.type = 0x00;
5415 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5416 sizeof(req_txp_cp), &req_txp_cp);
5417 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005418
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005419 /* Max TX power needs to be read only once per connection */
5420 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5421 req_txp_cp.handle = cpu_to_le16(conn->handle);
5422 req_txp_cp.type = 0x01;
5423 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5424 sizeof(req_txp_cp), &req_txp_cp);
5425 }
5426
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005427 err = hci_req_run(&req, conn_info_refresh_complete);
5428 if (err < 0)
5429 goto unlock;
5430
5431 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5432 data, len);
5433 if (!cmd) {
5434 err = -ENOMEM;
5435 goto unlock;
5436 }
5437
5438 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005439 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005440 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005441
5442 conn->conn_info_timestamp = jiffies;
5443 } else {
5444 /* Cache is valid, just reply with values cached in hci_conn */
5445 rp.rssi = conn->rssi;
5446 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005447 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005448
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005449 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5450 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005451 }
5452
5453unlock:
5454 hci_dev_unlock(hdev);
5455 return err;
5456}
5457
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005458static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005459{
5460 struct hci_conn *conn = cmd->user_data;
5461 struct mgmt_rp_get_clock_info rp;
5462 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005463 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005464
5465 memset(&rp, 0, sizeof(rp));
5466 memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
5467
5468 if (status)
5469 goto complete;
5470
5471 hdev = hci_dev_get(cmd->index);
5472 if (hdev) {
5473 rp.local_clock = cpu_to_le32(hdev->clock);
5474 hci_dev_put(hdev);
5475 }
5476
5477 if (conn) {
5478 rp.piconet_clock = cpu_to_le32(conn->clock);
5479 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5480 }
5481
5482complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005483 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5484 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005485
5486 if (conn) {
5487 hci_conn_drop(conn);
5488 hci_conn_put(conn);
5489 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005490
5491 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005492}
5493
Marcel Holtmann1904a852015-01-11 13:50:44 -08005494static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005495{
Johan Hedberg95868422014-06-28 17:54:07 +03005496 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005497 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005498 struct hci_conn *conn;
5499
5500 BT_DBG("%s status %u", hdev->name, status);
5501
5502 hci_dev_lock(hdev);
5503
5504 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5505 if (!hci_cp)
5506 goto unlock;
5507
5508 if (hci_cp->which) {
5509 u16 handle = __le16_to_cpu(hci_cp->handle);
5510 conn = hci_conn_hash_lookup_handle(hdev, handle);
5511 } else {
5512 conn = NULL;
5513 }
5514
Johan Hedberg333ae952015-03-17 13:48:47 +02005515 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005516 if (!cmd)
5517 goto unlock;
5518
Johan Hedberg69487372014-12-05 13:36:07 +02005519 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005520 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005521
5522unlock:
5523 hci_dev_unlock(hdev);
5524}
5525
5526static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5527 u16 len)
5528{
5529 struct mgmt_cp_get_clock_info *cp = data;
5530 struct mgmt_rp_get_clock_info rp;
5531 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005532 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005533 struct hci_request req;
5534 struct hci_conn *conn;
5535 int err;
5536
5537 BT_DBG("%s", hdev->name);
5538
5539 memset(&rp, 0, sizeof(rp));
5540 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5541 rp.addr.type = cp->addr.type;
5542
5543 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005544 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5545 MGMT_STATUS_INVALID_PARAMS,
5546 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005547
5548 hci_dev_lock(hdev);
5549
5550 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005551 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5552 MGMT_STATUS_NOT_POWERED, &rp,
5553 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005554 goto unlock;
5555 }
5556
5557 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5558 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5559 &cp->addr.bdaddr);
5560 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005561 err = mgmt_cmd_complete(sk, hdev->id,
5562 MGMT_OP_GET_CLOCK_INFO,
5563 MGMT_STATUS_NOT_CONNECTED,
5564 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005565 goto unlock;
5566 }
5567 } else {
5568 conn = NULL;
5569 }
5570
5571 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5572 if (!cmd) {
5573 err = -ENOMEM;
5574 goto unlock;
5575 }
5576
Johan Hedberg69487372014-12-05 13:36:07 +02005577 cmd->cmd_complete = clock_info_cmd_complete;
5578
Johan Hedberg95868422014-06-28 17:54:07 +03005579 hci_req_init(&req, hdev);
5580
5581 memset(&hci_cp, 0, sizeof(hci_cp));
5582 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5583
5584 if (conn) {
5585 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005586 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005587
5588 hci_cp.handle = cpu_to_le16(conn->handle);
5589 hci_cp.which = 0x01; /* Piconet clock */
5590 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5591 }
5592
5593 err = hci_req_run(&req, get_clock_info_complete);
5594 if (err < 0)
5595 mgmt_pending_remove(cmd);
5596
5597unlock:
5598 hci_dev_unlock(hdev);
5599 return err;
5600}
5601
Johan Hedberg5a154e62014-12-19 22:26:02 +02005602static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5603{
5604 struct hci_conn *conn;
5605
5606 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5607 if (!conn)
5608 return false;
5609
5610 if (conn->dst_type != type)
5611 return false;
5612
5613 if (conn->state != BT_CONNECTED)
5614 return false;
5615
5616 return true;
5617}
5618
5619/* This function requires the caller holds hdev->lock */
5620static int hci_conn_params_set(struct hci_request *req, bdaddr_t *addr,
5621 u8 addr_type, u8 auto_connect)
5622{
5623 struct hci_dev *hdev = req->hdev;
5624 struct hci_conn_params *params;
5625
5626 params = hci_conn_params_add(hdev, addr, addr_type);
5627 if (!params)
5628 return -EIO;
5629
5630 if (params->auto_connect == auto_connect)
5631 return 0;
5632
5633 list_del_init(&params->action);
5634
5635 switch (auto_connect) {
5636 case HCI_AUTO_CONN_DISABLED:
5637 case HCI_AUTO_CONN_LINK_LOSS:
5638 __hci_update_background_scan(req);
5639 break;
5640 case HCI_AUTO_CONN_REPORT:
5641 list_add(&params->action, &hdev->pend_le_reports);
5642 __hci_update_background_scan(req);
5643 break;
5644 case HCI_AUTO_CONN_DIRECT:
5645 case HCI_AUTO_CONN_ALWAYS:
5646 if (!is_connected(hdev, addr, addr_type)) {
5647 list_add(&params->action, &hdev->pend_le_conns);
5648 __hci_update_background_scan(req);
5649 }
5650 break;
5651 }
5652
5653 params->auto_connect = auto_connect;
5654
5655 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5656 auto_connect);
5657
5658 return 0;
5659}
5660
Marcel Holtmann8afef092014-06-29 22:28:34 +02005661static void device_added(struct sock *sk, struct hci_dev *hdev,
5662 bdaddr_t *bdaddr, u8 type, u8 action)
5663{
5664 struct mgmt_ev_device_added ev;
5665
5666 bacpy(&ev.addr.bdaddr, bdaddr);
5667 ev.addr.type = type;
5668 ev.action = action;
5669
5670 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5671}
5672
Marcel Holtmann1904a852015-01-11 13:50:44 -08005673static void add_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg5a154e62014-12-19 22:26:02 +02005674{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005675 struct mgmt_pending_cmd *cmd;
Johan Hedberg5a154e62014-12-19 22:26:02 +02005676
5677 BT_DBG("status 0x%02x", status);
5678
5679 hci_dev_lock(hdev);
5680
Johan Hedberg333ae952015-03-17 13:48:47 +02005681 cmd = pending_find(MGMT_OP_ADD_DEVICE, hdev);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005682 if (!cmd)
5683 goto unlock;
5684
5685 cmd->cmd_complete(cmd, mgmt_status(status));
5686 mgmt_pending_remove(cmd);
5687
5688unlock:
5689 hci_dev_unlock(hdev);
5690}
5691
Marcel Holtmann2faade52014-06-29 19:44:03 +02005692static int add_device(struct sock *sk, struct hci_dev *hdev,
5693 void *data, u16 len)
5694{
5695 struct mgmt_cp_add_device *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005696 struct mgmt_pending_cmd *cmd;
Johan Hedberg5a154e62014-12-19 22:26:02 +02005697 struct hci_request req;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005698 u8 auto_conn, addr_type;
5699 int err;
5700
5701 BT_DBG("%s", hdev->name);
5702
Johan Hedberg66593582014-07-09 12:59:14 +03005703 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005704 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005705 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5706 MGMT_STATUS_INVALID_PARAMS,
5707 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005708
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005709 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005710 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5711 MGMT_STATUS_INVALID_PARAMS,
5712 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005713
Johan Hedberg5a154e62014-12-19 22:26:02 +02005714 hci_req_init(&req, hdev);
5715
Marcel Holtmann2faade52014-06-29 19:44:03 +02005716 hci_dev_lock(hdev);
5717
Johan Hedberg5a154e62014-12-19 22:26:02 +02005718 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_DEVICE, hdev, data, len);
5719 if (!cmd) {
5720 err = -ENOMEM;
5721 goto unlock;
5722 }
5723
5724 cmd->cmd_complete = addr_cmd_complete;
5725
Johan Hedberg66593582014-07-09 12:59:14 +03005726 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005727 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005728 if (cp->action != 0x01) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005729 err = cmd->cmd_complete(cmd,
5730 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005731 mgmt_pending_remove(cmd);
Johan Hedberg66593582014-07-09 12:59:14 +03005732 goto unlock;
5733 }
5734
5735 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5736 cp->addr.type);
5737 if (err)
5738 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005739
Johan Hedberg5a154e62014-12-19 22:26:02 +02005740 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03005741
Johan Hedberg66593582014-07-09 12:59:14 +03005742 goto added;
5743 }
5744
Marcel Holtmann2faade52014-06-29 19:44:03 +02005745 if (cp->addr.type == BDADDR_LE_PUBLIC)
5746 addr_type = ADDR_LE_DEV_PUBLIC;
5747 else
5748 addr_type = ADDR_LE_DEV_RANDOM;
5749
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005750 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005751 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005752 else if (cp->action == 0x01)
5753 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005754 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005755 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005756
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005757 /* If the connection parameters don't exist for this device,
5758 * they will be created and configured with defaults.
5759 */
Johan Hedberg5a154e62014-12-19 22:26:02 +02005760 if (hci_conn_params_set(&req, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005761 auto_conn) < 0) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005762 err = cmd->cmd_complete(cmd, MGMT_STATUS_FAILED);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005763 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005764 goto unlock;
5765 }
5766
Johan Hedberg66593582014-07-09 12:59:14 +03005767added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005768 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5769
Johan Hedberg5a154e62014-12-19 22:26:02 +02005770 err = hci_req_run(&req, add_device_complete);
5771 if (err < 0) {
5772 /* ENODATA means no HCI commands were needed (e.g. if
5773 * the adapter is powered off).
5774 */
Johan Hedberg9df74652014-12-19 22:26:03 +02005775 if (err == -ENODATA)
5776 err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005777 mgmt_pending_remove(cmd);
5778 }
Marcel Holtmann2faade52014-06-29 19:44:03 +02005779
5780unlock:
5781 hci_dev_unlock(hdev);
5782 return err;
5783}
5784
Marcel Holtmann8afef092014-06-29 22:28:34 +02005785static void device_removed(struct sock *sk, struct hci_dev *hdev,
5786 bdaddr_t *bdaddr, u8 type)
5787{
5788 struct mgmt_ev_device_removed ev;
5789
5790 bacpy(&ev.addr.bdaddr, bdaddr);
5791 ev.addr.type = type;
5792
5793 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5794}
5795
Marcel Holtmann1904a852015-01-11 13:50:44 -08005796static void remove_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005797{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005798 struct mgmt_pending_cmd *cmd;
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005799
5800 BT_DBG("status 0x%02x", status);
5801
5802 hci_dev_lock(hdev);
5803
Johan Hedberg333ae952015-03-17 13:48:47 +02005804 cmd = pending_find(MGMT_OP_REMOVE_DEVICE, hdev);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005805 if (!cmd)
5806 goto unlock;
5807
5808 cmd->cmd_complete(cmd, mgmt_status(status));
5809 mgmt_pending_remove(cmd);
5810
5811unlock:
5812 hci_dev_unlock(hdev);
5813}
5814
Marcel Holtmann2faade52014-06-29 19:44:03 +02005815static int remove_device(struct sock *sk, struct hci_dev *hdev,
5816 void *data, u16 len)
5817{
5818 struct mgmt_cp_remove_device *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005819 struct mgmt_pending_cmd *cmd;
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005820 struct hci_request req;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005821 int err;
5822
5823 BT_DBG("%s", hdev->name);
5824
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005825 hci_req_init(&req, hdev);
5826
Marcel Holtmann2faade52014-06-29 19:44:03 +02005827 hci_dev_lock(hdev);
5828
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005829 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_DEVICE, hdev, data, len);
5830 if (!cmd) {
5831 err = -ENOMEM;
5832 goto unlock;
5833 }
5834
5835 cmd->cmd_complete = addr_cmd_complete;
5836
Marcel Holtmann2faade52014-06-29 19:44:03 +02005837 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005838 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005839 u8 addr_type;
5840
Johan Hedberg66593582014-07-09 12:59:14 +03005841 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005842 err = cmd->cmd_complete(cmd,
5843 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005844 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005845 goto unlock;
5846 }
5847
Johan Hedberg66593582014-07-09 12:59:14 +03005848 if (cp->addr.type == BDADDR_BREDR) {
5849 err = hci_bdaddr_list_del(&hdev->whitelist,
5850 &cp->addr.bdaddr,
5851 cp->addr.type);
5852 if (err) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005853 err = cmd->cmd_complete(cmd,
5854 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005855 mgmt_pending_remove(cmd);
Johan Hedberg66593582014-07-09 12:59:14 +03005856 goto unlock;
5857 }
5858
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005859 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03005860
Johan Hedberg66593582014-07-09 12:59:14 +03005861 device_removed(sk, hdev, &cp->addr.bdaddr,
5862 cp->addr.type);
5863 goto complete;
5864 }
5865
Marcel Holtmann2faade52014-06-29 19:44:03 +02005866 if (cp->addr.type == BDADDR_LE_PUBLIC)
5867 addr_type = ADDR_LE_DEV_PUBLIC;
5868 else
5869 addr_type = ADDR_LE_DEV_RANDOM;
5870
Johan Hedbergc71593d2014-07-02 17:37:28 +03005871 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5872 addr_type);
5873 if (!params) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005874 err = cmd->cmd_complete(cmd,
5875 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005876 mgmt_pending_remove(cmd);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005877 goto unlock;
5878 }
5879
5880 if (params->auto_connect == HCI_AUTO_CONN_DISABLED) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005881 err = cmd->cmd_complete(cmd,
5882 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005883 mgmt_pending_remove(cmd);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005884 goto unlock;
5885 }
5886
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005887 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005888 list_del(&params->list);
5889 kfree(params);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005890 __hci_update_background_scan(&req);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005891
5892 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005893 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005894 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005895 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005896
Marcel Holtmann2faade52014-06-29 19:44:03 +02005897 if (cp->addr.type) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005898 err = cmd->cmd_complete(cmd,
5899 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005900 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005901 goto unlock;
5902 }
5903
Johan Hedberg66593582014-07-09 12:59:14 +03005904 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5905 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5906 list_del(&b->list);
5907 kfree(b);
5908 }
5909
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005910 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03005911
Johan Hedberg19de0822014-07-06 13:06:51 +03005912 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5913 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5914 continue;
5915 device_removed(sk, hdev, &p->addr, p->addr_type);
5916 list_del(&p->action);
5917 list_del(&p->list);
5918 kfree(p);
5919 }
5920
5921 BT_DBG("All LE connection parameters were removed");
5922
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005923 __hci_update_background_scan(&req);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005924 }
5925
Johan Hedberg66593582014-07-09 12:59:14 +03005926complete:
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005927 err = hci_req_run(&req, remove_device_complete);
5928 if (err < 0) {
5929 /* ENODATA means no HCI commands were needed (e.g. if
5930 * the adapter is powered off).
5931 */
Johan Hedberg9df74652014-12-19 22:26:03 +02005932 if (err == -ENODATA)
5933 err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005934 mgmt_pending_remove(cmd);
5935 }
Marcel Holtmann2faade52014-06-29 19:44:03 +02005936
5937unlock:
5938 hci_dev_unlock(hdev);
5939 return err;
5940}
5941
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005942static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5943 u16 len)
5944{
5945 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005946 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5947 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005948 u16 param_count, expected_len;
5949 int i;
5950
5951 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005952 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5953 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005954
5955 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005956 if (param_count > max_param_count) {
5957 BT_ERR("load_conn_param: too big param_count value %u",
5958 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005959 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5960 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005961 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005962
5963 expected_len = sizeof(*cp) + param_count *
5964 sizeof(struct mgmt_conn_param);
5965 if (expected_len != len) {
5966 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
5967 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005968 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5969 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005970 }
5971
5972 BT_DBG("%s param_count %u", hdev->name, param_count);
5973
5974 hci_dev_lock(hdev);
5975
5976 hci_conn_params_clear_disabled(hdev);
5977
5978 for (i = 0; i < param_count; i++) {
5979 struct mgmt_conn_param *param = &cp->params[i];
5980 struct hci_conn_params *hci_param;
5981 u16 min, max, latency, timeout;
5982 u8 addr_type;
5983
5984 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
5985 param->addr.type);
5986
5987 if (param->addr.type == BDADDR_LE_PUBLIC) {
5988 addr_type = ADDR_LE_DEV_PUBLIC;
5989 } else if (param->addr.type == BDADDR_LE_RANDOM) {
5990 addr_type = ADDR_LE_DEV_RANDOM;
5991 } else {
5992 BT_ERR("Ignoring invalid connection parameters");
5993 continue;
5994 }
5995
5996 min = le16_to_cpu(param->min_interval);
5997 max = le16_to_cpu(param->max_interval);
5998 latency = le16_to_cpu(param->latency);
5999 timeout = le16_to_cpu(param->timeout);
6000
6001 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6002 min, max, latency, timeout);
6003
6004 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
6005 BT_ERR("Ignoring invalid connection parameters");
6006 continue;
6007 }
6008
6009 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
6010 addr_type);
6011 if (!hci_param) {
6012 BT_ERR("Failed to add connection parameters");
6013 continue;
6014 }
6015
6016 hci_param->conn_min_interval = min;
6017 hci_param->conn_max_interval = max;
6018 hci_param->conn_latency = latency;
6019 hci_param->supervision_timeout = timeout;
6020 }
6021
6022 hci_dev_unlock(hdev);
6023
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006024 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
6025 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006026}
6027
Marcel Holtmanndbece372014-07-04 18:11:55 +02006028static int set_external_config(struct sock *sk, struct hci_dev *hdev,
6029 void *data, u16 len)
6030{
6031 struct mgmt_cp_set_external_config *cp = data;
6032 bool changed;
6033 int err;
6034
6035 BT_DBG("%s", hdev->name);
6036
6037 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006038 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6039 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006040
6041 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006042 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6043 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006044
6045 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02006046 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6047 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006048
6049 hci_dev_lock(hdev);
6050
6051 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07006052 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006053 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006054 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006055
6056 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
6057 if (err < 0)
6058 goto unlock;
6059
6060 if (!changed)
6061 goto unlock;
6062
Marcel Holtmannf4537c02014-07-04 19:06:23 +02006063 err = new_options(hdev, sk);
6064
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006065 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02006066 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006067
Marcel Holtmann516018a2015-03-13 02:11:04 -07006068 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006069 hci_dev_set_flag(hdev, HCI_CONFIG);
6070 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006071
6072 queue_work(hdev->req_workqueue, &hdev->power_on);
6073 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02006074 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006075 mgmt_index_added(hdev);
6076 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02006077 }
6078
6079unlock:
6080 hci_dev_unlock(hdev);
6081 return err;
6082}
6083
Marcel Holtmann9713c172014-07-06 12:11:15 +02006084static int set_public_address(struct sock *sk, struct hci_dev *hdev,
6085 void *data, u16 len)
6086{
6087 struct mgmt_cp_set_public_address *cp = data;
6088 bool changed;
6089 int err;
6090
6091 BT_DBG("%s", hdev->name);
6092
6093 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006094 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6095 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006096
6097 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02006098 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6099 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006100
6101 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02006102 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6103 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006104
6105 hci_dev_lock(hdev);
6106
6107 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
6108 bacpy(&hdev->public_addr, &cp->bdaddr);
6109
6110 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
6111 if (err < 0)
6112 goto unlock;
6113
6114 if (!changed)
6115 goto unlock;
6116
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006117 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006118 err = new_options(hdev, sk);
6119
6120 if (is_configured(hdev)) {
6121 mgmt_index_removed(hdev);
6122
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006123 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006124
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006125 hci_dev_set_flag(hdev, HCI_CONFIG);
6126 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006127
6128 queue_work(hdev->req_workqueue, &hdev->power_on);
6129 }
6130
6131unlock:
6132 hci_dev_unlock(hdev);
6133 return err;
6134}
6135
Marcel Holtmannbea41602015-03-14 22:43:17 -07006136static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
6137 u8 data_len)
6138{
6139 eir[eir_len++] = sizeof(type) + data_len;
6140 eir[eir_len++] = type;
6141 memcpy(&eir[eir_len], data, data_len);
6142 eir_len += data_len;
6143
6144 return eir_len;
6145}
6146
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006147static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
6148 void *data, u16 data_len)
6149{
6150 struct mgmt_cp_read_local_oob_ext_data *cp = data;
6151 struct mgmt_rp_read_local_oob_ext_data *rp;
6152 size_t rp_len;
6153 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006154 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006155 int err;
6156
6157 BT_DBG("%s", hdev->name);
6158
6159 if (!hdev_is_powered(hdev))
6160 return mgmt_cmd_complete(sk, hdev->id,
6161 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6162 MGMT_STATUS_NOT_POWERED,
6163 &cp->type, sizeof(cp->type));
6164
6165 switch (cp->type) {
6166 case BIT(BDADDR_BREDR):
6167 status = mgmt_bredr_support(hdev);
6168 if (status)
6169 return mgmt_cmd_complete(sk, hdev->id,
6170 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6171 status, &cp->type,
6172 sizeof(cp->type));
6173 eir_len = 5;
6174 break;
6175 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6176 status = mgmt_le_support(hdev);
6177 if (status)
6178 return mgmt_cmd_complete(sk, hdev->id,
6179 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6180 status, &cp->type,
6181 sizeof(cp->type));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006182 eir_len = 9 + 3 + 18 + 18 + 3;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006183 break;
6184 default:
6185 return mgmt_cmd_complete(sk, hdev->id,
6186 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6187 MGMT_STATUS_INVALID_PARAMS,
6188 &cp->type, sizeof(cp->type));
6189 }
6190
6191 hci_dev_lock(hdev);
6192
6193 rp_len = sizeof(*rp) + eir_len;
6194 rp = kmalloc(rp_len, GFP_ATOMIC);
6195 if (!rp) {
6196 hci_dev_unlock(hdev);
6197 return -ENOMEM;
6198 }
6199
6200 eir_len = 0;
6201 switch (cp->type) {
6202 case BIT(BDADDR_BREDR):
6203 eir_len = eir_append_data(rp->eir, eir_len, EIR_CLASS_OF_DEV,
6204 hdev->dev_class, 3);
6205 break;
6206 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07006207 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6208 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006209 hci_dev_unlock(hdev);
6210 err = mgmt_cmd_complete(sk, hdev->id,
Marcel Holtmann5082a592015-03-16 12:39:00 -07006211 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6212 MGMT_STATUS_FAILED,
6213 &cp->type, sizeof(cp->type));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006214 goto done;
6215 }
6216
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006217 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
6218 memcpy(addr, &hdev->rpa, 6);
6219 addr[6] = 0x01;
6220 } else if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
6221 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
6222 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
6223 bacmp(&hdev->static_addr, BDADDR_ANY))) {
6224 memcpy(addr, &hdev->static_addr, 6);
6225 addr[6] = 0x01;
6226 } else {
6227 memcpy(addr, &hdev->bdaddr, 6);
6228 addr[6] = 0x00;
6229 }
6230
6231 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
6232 addr, sizeof(addr));
6233
6234 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
6235 role = 0x02;
6236 else
6237 role = 0x01;
6238
6239 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
6240 &role, sizeof(role));
6241
Marcel Holtmann5082a592015-03-16 12:39:00 -07006242 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
6243 eir_len = eir_append_data(rp->eir, eir_len,
6244 EIR_LE_SC_CONFIRM,
6245 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006246
Marcel Holtmann5082a592015-03-16 12:39:00 -07006247 eir_len = eir_append_data(rp->eir, eir_len,
6248 EIR_LE_SC_RANDOM,
6249 rand, sizeof(rand));
6250 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006251
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006252 flags = get_adv_discov_flags(hdev);
6253
6254 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
6255 flags |= LE_AD_NO_BREDR;
6256
6257 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
6258 &flags, sizeof(flags));
6259 break;
6260 }
6261
6262 rp->type = cp->type;
6263 rp->eir_len = cpu_to_le16(eir_len);
6264
6265 hci_dev_unlock(hdev);
6266
Marcel Holtmann72000df2015-03-16 16:11:21 -07006267 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
6268
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006269 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann5425f982015-03-16 16:05:44 -07006270 MGMT_STATUS_SUCCESS, rp, sizeof(*rp) + eir_len);
Marcel Holtmann72000df2015-03-16 16:11:21 -07006271 if (err < 0)
6272 goto done;
6273
6274 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6275 rp, sizeof(*rp) + eir_len,
6276 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006277
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006278done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006279 kfree(rp);
6280
6281 return err;
6282}
6283
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006284static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6285 void *data, u16 data_len)
6286{
6287 struct mgmt_rp_read_adv_features *rp;
6288 size_t rp_len;
6289 int err;
6290
6291 BT_DBG("%s", hdev->name);
6292
6293 hci_dev_lock(hdev);
6294
6295 rp_len = sizeof(*rp);
6296 rp = kmalloc(rp_len, GFP_ATOMIC);
6297 if (!rp) {
6298 hci_dev_unlock(hdev);
6299 return -ENOMEM;
6300 }
6301
6302 rp->supported_flags = cpu_to_le32(0);
6303 rp->max_adv_data_len = 31;
6304 rp->max_scan_rsp_len = 31;
6305 rp->max_instances = 0;
6306 rp->num_instances = 0;
6307
6308 hci_dev_unlock(hdev);
6309
6310 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6311 MGMT_STATUS_SUCCESS, rp, rp_len);
6312
6313 kfree(rp);
6314
6315 return err;
6316}
6317
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006318static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006319 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006320 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006321 HCI_MGMT_NO_HDEV |
6322 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006323 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006324 HCI_MGMT_NO_HDEV |
6325 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006326 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006327 HCI_MGMT_NO_HDEV |
6328 HCI_MGMT_UNTRUSTED },
6329 { read_controller_info, MGMT_READ_INFO_SIZE,
6330 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006331 { set_powered, MGMT_SETTING_SIZE },
6332 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6333 { set_connectable, MGMT_SETTING_SIZE },
6334 { set_fast_connectable, MGMT_SETTING_SIZE },
6335 { set_bondable, MGMT_SETTING_SIZE },
6336 { set_link_security, MGMT_SETTING_SIZE },
6337 { set_ssp, MGMT_SETTING_SIZE },
6338 { set_hs, MGMT_SETTING_SIZE },
6339 { set_le, MGMT_SETTING_SIZE },
6340 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6341 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6342 { add_uuid, MGMT_ADD_UUID_SIZE },
6343 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006344 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6345 HCI_MGMT_VAR_LEN },
6346 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6347 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006348 { disconnect, MGMT_DISCONNECT_SIZE },
6349 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6350 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6351 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6352 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6353 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6354 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6355 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6356 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6357 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6358 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6359 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006360 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6361 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6362 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006363 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6364 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6365 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6366 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6367 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6368 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6369 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6370 { set_advertising, MGMT_SETTING_SIZE },
6371 { set_bredr, MGMT_SETTING_SIZE },
6372 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6373 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6374 { set_secure_conn, MGMT_SETTING_SIZE },
6375 { set_debug_keys, MGMT_SETTING_SIZE },
6376 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006377 { load_irks, MGMT_LOAD_IRKS_SIZE,
6378 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006379 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6380 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6381 { add_device, MGMT_ADD_DEVICE_SIZE },
6382 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006383 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6384 HCI_MGMT_VAR_LEN },
6385 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006386 HCI_MGMT_NO_HDEV |
6387 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006388 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006389 HCI_MGMT_UNCONFIGURED |
6390 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006391 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6392 HCI_MGMT_UNCONFIGURED },
6393 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6394 HCI_MGMT_UNCONFIGURED },
6395 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6396 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006397 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006398 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006399 HCI_MGMT_NO_HDEV |
6400 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006401 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006402};
6403
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006404int mgmt_control(struct hci_mgmt_chan *chan, struct sock *sk,
6405 struct msghdr *msg, size_t msglen)
Johan Hedberg03811012010-12-08 00:21:06 +02006406{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03006407 void *buf;
6408 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02006409 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01006410 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006411 struct hci_dev *hdev = NULL;
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006412 const struct hci_mgmt_handler *handler;
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006413 bool var_len, no_hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02006414 int err;
6415
6416 BT_DBG("got %zu bytes", msglen);
6417
6418 if (msglen < sizeof(*hdr))
6419 return -EINVAL;
6420
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03006421 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02006422 if (!buf)
6423 return -ENOMEM;
6424
Al Viro6ce8e9c2014-04-06 21:25:44 -04006425 if (memcpy_from_msg(buf, msg, msglen)) {
Johan Hedberg03811012010-12-08 00:21:06 +02006426 err = -EFAULT;
6427 goto done;
6428 }
6429
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03006430 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07006431 opcode = __le16_to_cpu(hdr->opcode);
6432 index = __le16_to_cpu(hdr->index);
6433 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02006434
6435 if (len != msglen - sizeof(*hdr)) {
6436 err = -EINVAL;
6437 goto done;
6438 }
6439
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006440 if (opcode >= chan->handler_count ||
6441 chan->handlers[opcode].func == NULL) {
6442 BT_DBG("Unknown op %u", opcode);
Johan Hedberga69e8372015-03-06 21:08:53 +02006443 err = mgmt_cmd_status(sk, index, opcode,
6444 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006445 goto done;
6446 }
6447
6448 handler = &chan->handlers[opcode];
6449
Marcel Holtmannc927a102015-03-14 19:28:03 -07006450 if (!hci_sock_test_flag(sk, HCI_SOCK_TRUSTED) &&
6451 !(handler->flags & HCI_MGMT_UNTRUSTED)) {
6452 err = mgmt_cmd_status(sk, index, opcode,
6453 MGMT_STATUS_PERMISSION_DENIED);
6454 goto done;
6455 }
6456
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006457 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006458 hdev = hci_dev_get(index);
6459 if (!hdev) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006460 err = mgmt_cmd_status(sk, index, opcode,
6461 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006462 goto done;
6463 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07006464
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006465 if (hci_dev_test_flag(hdev, HCI_SETUP) ||
6466 hci_dev_test_flag(hdev, HCI_CONFIG) ||
6467 hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006468 err = mgmt_cmd_status(sk, index, opcode,
6469 MGMT_STATUS_INVALID_INDEX);
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07006470 goto done;
6471 }
Marcel Holtmann42a9bc142014-07-04 16:54:40 +02006472
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006473 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006474 !(handler->flags & HCI_MGMT_UNCONFIGURED)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006475 err = mgmt_cmd_status(sk, index, opcode,
6476 MGMT_STATUS_INVALID_INDEX);
Marcel Holtmann42a9bc142014-07-04 16:54:40 +02006477 goto done;
6478 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006479 }
6480
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006481 no_hdev = (handler->flags & HCI_MGMT_NO_HDEV);
6482 if (no_hdev != !hdev) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006483 err = mgmt_cmd_status(sk, index, opcode,
6484 MGMT_STATUS_INVALID_INDEX);
Marcel Holtmann73d1df22014-07-02 22:10:52 +02006485 goto done;
6486 }
6487
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006488 var_len = (handler->flags & HCI_MGMT_VAR_LEN);
6489 if ((var_len && len < handler->data_len) ||
6490 (!var_len && len != handler->data_len)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006491 err = mgmt_cmd_status(sk, index, opcode,
6492 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02006493 goto done;
6494 }
6495
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006496 if (hdev)
6497 mgmt_init_hdev(sk, hdev);
6498
6499 cp = buf + sizeof(*hdr);
6500
Johan Hedbergbe22b542012-03-01 22:24:41 +02006501 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02006502 if (err < 0)
6503 goto done;
6504
Johan Hedberg03811012010-12-08 00:21:06 +02006505 err = msglen;
6506
6507done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006508 if (hdev)
6509 hci_dev_put(hdev);
6510
Johan Hedberg03811012010-12-08 00:21:06 +02006511 kfree(buf);
6512 return err;
6513}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006514
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006515void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006516{
Marcel Holtmannced85542015-03-14 19:27:56 -07006517 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006518
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006519 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6520 return;
6521
Marcel Holtmannf9207332015-03-14 19:27:55 -07006522 switch (hdev->dev_type) {
6523 case HCI_BREDR:
6524 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6525 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6526 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006527 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006528 } else {
6529 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6530 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006531 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006532 }
6533 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006534 case HCI_AMP:
6535 ev.type = 0x02;
6536 break;
6537 default:
6538 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006539 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006540
6541 ev.bus = hdev->bus;
6542
6543 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6544 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006545}
6546
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006547void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006548{
Marcel Holtmannced85542015-03-14 19:27:56 -07006549 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006550 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006551
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006552 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6553 return;
6554
Marcel Holtmannf9207332015-03-14 19:27:55 -07006555 switch (hdev->dev_type) {
6556 case HCI_BREDR:
6557 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006558
Marcel Holtmannf9207332015-03-14 19:27:55 -07006559 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6560 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6561 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006562 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006563 } else {
6564 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6565 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006566 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006567 }
6568 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006569 case HCI_AMP:
6570 ev.type = 0x02;
6571 break;
6572 default:
6573 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006574 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006575
6576 ev.bus = hdev->bus;
6577
6578 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6579 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006580}
6581
Andre Guedes6046dc32014-02-26 20:21:51 -03006582/* This function requires the caller holds hdev->lock */
Johan Hedberg2cf22212014-12-19 22:26:00 +02006583static void restart_le_actions(struct hci_request *req)
Andre Guedes6046dc32014-02-26 20:21:51 -03006584{
Johan Hedberg2cf22212014-12-19 22:26:00 +02006585 struct hci_dev *hdev = req->hdev;
Andre Guedes6046dc32014-02-26 20:21:51 -03006586 struct hci_conn_params *p;
6587
6588 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006589 /* Needed for AUTO_OFF case where might not "really"
6590 * have been powered off.
6591 */
6592 list_del_init(&p->action);
6593
6594 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006595 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006596 case HCI_AUTO_CONN_ALWAYS:
6597 list_add(&p->action, &hdev->pend_le_conns);
6598 break;
6599 case HCI_AUTO_CONN_REPORT:
6600 list_add(&p->action, &hdev->pend_le_reports);
6601 break;
6602 default:
6603 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006604 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006605 }
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006606
Johan Hedberg2cf22212014-12-19 22:26:00 +02006607 __hci_update_background_scan(req);
Andre Guedes6046dc32014-02-26 20:21:51 -03006608}
6609
Marcel Holtmann1904a852015-01-11 13:50:44 -08006610static void powered_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg229ab392013-03-15 17:06:53 -05006611{
6612 struct cmd_lookup match = { NULL, hdev };
6613
6614 BT_DBG("status 0x%02x", status);
6615
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006616 if (!status) {
6617 /* Register the available SMP channels (BR/EDR and LE) only
6618 * when successfully powering on the controller. This late
6619 * registration is required so that LE SMP can clearly
6620 * decide if the public address or static address is used.
6621 */
6622 smp_register(hdev);
6623 }
6624
Johan Hedberg229ab392013-03-15 17:06:53 -05006625 hci_dev_lock(hdev);
6626
6627 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6628
6629 new_settings(hdev, match.sk);
6630
6631 hci_dev_unlock(hdev);
6632
6633 if (match.sk)
6634 sock_put(match.sk);
6635}
6636
Johan Hedberg70da6242013-03-15 17:06:51 -05006637static int powered_update_hci(struct hci_dev *hdev)
6638{
Johan Hedberg890ea892013-03-15 17:06:52 -05006639 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05006640 u8 link_sec;
6641
Johan Hedberg890ea892013-03-15 17:06:52 -05006642 hci_req_init(&req, hdev);
6643
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006644 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED) &&
Johan Hedberg70da6242013-03-15 17:06:51 -05006645 !lmp_host_ssp_capable(hdev)) {
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006646 u8 mode = 0x01;
Johan Hedberg70da6242013-03-15 17:06:51 -05006647
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006648 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
Johan Hedberg70da6242013-03-15 17:06:51 -05006649
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006650 if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) {
6651 u8 support = 0x01;
6652
6653 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT,
6654 sizeof(support), &support);
6655 }
Johan Hedbergec6f99b2014-12-12 13:30:11 +02006656 }
6657
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006658 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
Johan Hedbergc73eee92013-04-19 18:35:21 +03006659 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05006660 struct hci_cp_write_le_host_supported cp;
6661
Marcel Holtmann32226e42014-07-24 20:04:16 +02006662 cp.le = 0x01;
6663 cp.simul = 0x00;
Johan Hedberg70da6242013-03-15 17:06:51 -05006664
6665 /* Check first if we already have the right
6666 * host state (host features set)
6667 */
6668 if (cp.le != lmp_host_le_capable(hdev) ||
6669 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05006670 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
6671 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05006672 }
6673
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07006674 if (lmp_le_capable(hdev)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006675 /* Make sure the controller has a good default for
6676 * advertising data. This also applies to the case
6677 * where BR/EDR was toggled during the AUTO_OFF phase.
6678 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006679 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07006680 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07006681 update_scan_rsp_data(&req);
6682 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006683
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006684 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07006685 enable_advertising(&req);
Johan Hedberg2cf22212014-12-19 22:26:00 +02006686
6687 restart_le_actions(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03006688 }
6689
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006690 link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg70da6242013-03-15 17:06:51 -05006691 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05006692 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
6693 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05006694
6695 if (lmp_bredr_capable(hdev)) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006696 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg406ef2a2015-03-10 20:14:27 +02006697 write_fast_connectable(&req, true);
6698 else
6699 write_fast_connectable(&req, false);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02006700 __hci_update_page_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006701 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05006702 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006703 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05006704 }
6705
Johan Hedberg229ab392013-03-15 17:06:53 -05006706 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05006707}
6708
Johan Hedberg744cf192011-11-08 20:40:14 +02006709int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006710{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006711 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006712 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006713 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006714
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006715 if (!hci_dev_test_flag(hdev, HCI_MGMT))
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006716 return 0;
6717
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006718 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05006719 if (powered_update_hci(hdev) == 0)
6720 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02006721
Johan Hedberg229ab392013-03-15 17:06:53 -05006722 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
6723 &match);
6724 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006725 }
6726
Johan Hedberg229ab392013-03-15 17:06:53 -05006727 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006728
6729 /* If the power off is because of hdev unregistration let
6730 * use the appropriate INVALID_INDEX status. Otherwise use
6731 * NOT_POWERED. We cover both scenarios here since later in
6732 * mgmt_index_removed() any hci_conn callbacks will have already
6733 * been triggered, potentially causing misleading DISCONNECTED
6734 * status responses.
6735 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006736 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006737 status = MGMT_STATUS_INVALID_INDEX;
6738 else
6739 status = MGMT_STATUS_NOT_POWERED;
6740
6741 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006742
6743 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07006744 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6745 zero_cod, sizeof(zero_cod), NULL);
Johan Hedberg229ab392013-03-15 17:06:53 -05006746
6747new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02006748 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006749
6750 if (match.sk)
6751 sock_put(match.sk);
6752
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006753 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006754}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006755
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006756void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006757{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006758 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006759 u8 status;
6760
Johan Hedberg333ae952015-03-17 13:48:47 +02006761 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006762 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006763 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006764
6765 if (err == -ERFKILL)
6766 status = MGMT_STATUS_RFKILLED;
6767 else
6768 status = MGMT_STATUS_FAILED;
6769
Johan Hedberga69e8372015-03-06 21:08:53 +02006770 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006771
6772 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006773}
6774
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006775void mgmt_discoverable_timeout(struct hci_dev *hdev)
6776{
6777 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006778
6779 hci_dev_lock(hdev);
6780
6781 /* When discoverable timeout triggers, then just make sure
6782 * the limited discoverable flag is cleared. Even in the case
6783 * of a timeout triggered from general discoverable, it is
6784 * safe to unconditionally clear the flag.
6785 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006786 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
6787 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006788
6789 hci_req_init(&req, hdev);
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006790 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg4b580612013-10-19 23:38:21 +03006791 u8 scan = SCAN_PAGE;
6792 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
6793 sizeof(scan), &scan);
6794 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006795 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03006796 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006797 hci_req_run(&req, NULL);
6798
6799 hdev->discov_timeout = 0;
6800
Johan Hedberg9a43e252013-10-20 19:00:07 +03006801 new_settings(hdev, NULL);
6802
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006803 hci_dev_unlock(hdev);
6804}
6805
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006806void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
6807 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006808{
Johan Hedberg86742e12011-11-07 23:13:38 +02006809 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006810
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006811 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006812
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006813 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02006814 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006815 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006816 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03006817 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006818 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006819
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006820 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006821}
Johan Hedbergf7520542011-01-20 12:34:39 +02006822
Johan Hedbergd7b25452014-05-23 13:19:53 +03006823static u8 mgmt_ltk_type(struct smp_ltk *ltk)
6824{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006825 switch (ltk->type) {
6826 case SMP_LTK:
6827 case SMP_LTK_SLAVE:
6828 if (ltk->authenticated)
6829 return MGMT_LTK_AUTHENTICATED;
6830 return MGMT_LTK_UNAUTHENTICATED;
6831 case SMP_LTK_P256:
6832 if (ltk->authenticated)
6833 return MGMT_LTK_P256_AUTH;
6834 return MGMT_LTK_P256_UNAUTH;
6835 case SMP_LTK_P256_DEBUG:
6836 return MGMT_LTK_P256_DEBUG;
6837 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006838
6839 return MGMT_LTK_UNAUTHENTICATED;
6840}
6841
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006842void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006843{
6844 struct mgmt_ev_new_long_term_key ev;
6845
6846 memset(&ev, 0, sizeof(ev));
6847
Marcel Holtmann5192d302014-02-19 17:11:58 -08006848 /* Devices using resolvable or non-resolvable random addresses
6849 * without providing an indentity resolving key don't require
6850 * to store long term keys. Their addresses will change the
6851 * next time around.
6852 *
6853 * Only when a remote device provides an identity address
6854 * make sure the long term key is stored. If the remote
6855 * identity is known, the long term keys are internally
6856 * mapped to the identity address. So allow static random
6857 * and public addresses here.
6858 */
Johan Hedbergba74b662014-02-19 14:57:45 +02006859 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6860 (key->bdaddr.b[5] & 0xc0) != 0xc0)
6861 ev.store_hint = 0x00;
6862 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006863 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02006864
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006865 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006866 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03006867 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006868 ev.key.enc_size = key->enc_size;
6869 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08006870 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006871
Johan Hedberg2ceba532014-06-16 19:25:16 +03006872 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006873 ev.key.master = 1;
6874
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006875 memcpy(ev.key.val, key->val, sizeof(key->val));
6876
Marcel Holtmann083368f2013-10-15 14:26:29 -07006877 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006878}
6879
Johan Hedberg95fbac82014-02-19 15:18:31 +02006880void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk)
6881{
6882 struct mgmt_ev_new_irk ev;
6883
6884 memset(&ev, 0, sizeof(ev));
6885
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08006886 /* For identity resolving keys from devices that are already
6887 * using a public address or static random address, do not
6888 * ask for storing this key. The identity resolving key really
6889 * is only mandatory for devices using resovlable random
6890 * addresses.
6891 *
6892 * Storing all identity resolving keys has the downside that
6893 * they will be also loaded on next boot of they system. More
6894 * identity resolving keys, means more time during scanning is
6895 * needed to actually resolve these addresses.
6896 */
6897 if (bacmp(&irk->rpa, BDADDR_ANY))
6898 ev.store_hint = 0x01;
6899 else
6900 ev.store_hint = 0x00;
6901
Johan Hedberg95fbac82014-02-19 15:18:31 +02006902 bacpy(&ev.rpa, &irk->rpa);
6903 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
6904 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
6905 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
6906
6907 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
6908}
6909
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006910void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
6911 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006912{
6913 struct mgmt_ev_new_csrk ev;
6914
6915 memset(&ev, 0, sizeof(ev));
6916
6917 /* Devices using resolvable or non-resolvable random addresses
6918 * without providing an indentity resolving key don't require
6919 * to store signature resolving keys. Their addresses will change
6920 * the next time around.
6921 *
6922 * Only when a remote device provides an identity address
6923 * make sure the signature resolving key is stored. So allow
6924 * static random and public addresses here.
6925 */
6926 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6927 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
6928 ev.store_hint = 0x00;
6929 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006930 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006931
6932 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
6933 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02006934 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006935 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
6936
6937 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
6938}
6939
Andre Guedesffb5a8272014-07-01 18:10:11 -03006940void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03006941 u8 bdaddr_type, u8 store_hint, u16 min_interval,
6942 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03006943{
6944 struct mgmt_ev_new_conn_param ev;
6945
Johan Hedbergc103aea2014-07-02 17:37:34 +03006946 if (!hci_is_identity_address(bdaddr, bdaddr_type))
6947 return;
6948
Andre Guedesffb5a8272014-07-01 18:10:11 -03006949 memset(&ev, 0, sizeof(ev));
6950 bacpy(&ev.addr.bdaddr, bdaddr);
6951 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03006952 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03006953 ev.min_interval = cpu_to_le16(min_interval);
6954 ev.max_interval = cpu_to_le16(max_interval);
6955 ev.latency = cpu_to_le16(latency);
6956 ev.timeout = cpu_to_le16(timeout);
6957
6958 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
6959}
6960
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006961void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
6962 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02006963{
Johan Hedbergb644ba32012-01-17 21:48:47 +02006964 char buf[512];
6965 struct mgmt_ev_device_connected *ev = (void *) buf;
6966 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02006967
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006968 bacpy(&ev->addr.bdaddr, &conn->dst);
6969 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02006970
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02006971 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02006972
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006973 /* We must ensure that the EIR Data fields are ordered and
6974 * unique. Keep it simple for now and avoid the problem by not
6975 * adding any BR/EDR data to the LE adv.
6976 */
6977 if (conn->le_adv_data_len > 0) {
6978 memcpy(&ev->eir[eir_len],
6979 conn->le_adv_data, conn->le_adv_data_len);
6980 eir_len = conn->le_adv_data_len;
6981 } else {
6982 if (name_len > 0)
6983 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
6984 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006985
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00006986 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006987 eir_len = eir_append_data(ev->eir, eir_len,
6988 EIR_CLASS_OF_DEV,
6989 conn->dev_class, 3);
6990 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02006991
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02006992 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006993
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07006994 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
6995 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02006996}
6997
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006998static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006999{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007000 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007001
Johan Hedbergf5818c22014-12-05 13:36:02 +02007002 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007003
7004 *sk = cmd->sk;
7005 sock_hold(*sk);
7006
Johan Hedberga664b5b2011-02-19 12:06:02 -03007007 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007008}
7009
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007010static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007011{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007012 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007013 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007014
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007015 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7016
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007017 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007018 mgmt_pending_remove(cmd);
7019}
7020
Johan Hedberg84c61d92014-08-01 11:13:30 +03007021bool mgmt_powering_down(struct hci_dev *hdev)
7022{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007023 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007024 struct mgmt_mode *cp;
7025
Johan Hedberg333ae952015-03-17 13:48:47 +02007026 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03007027 if (!cmd)
7028 return false;
7029
7030 cp = cmd->param;
7031 if (!cp->val)
7032 return true;
7033
7034 return false;
7035}
7036
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007037void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007038 u8 link_type, u8 addr_type, u8 reason,
7039 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007040{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007041 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007042 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007043
Johan Hedberg84c61d92014-08-01 11:13:30 +03007044 /* The connection is still in hci_conn_hash so test for 1
7045 * instead of 0 to know if this is the last one.
7046 */
7047 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7048 cancel_delayed_work(&hdev->power_off);
7049 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007050 }
7051
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007052 if (!mgmt_connected)
7053 return;
7054
Andre Guedes57eb7762013-10-30 19:01:41 -03007055 if (link_type != ACL_LINK && link_type != LE_LINK)
7056 return;
7057
Johan Hedberg744cf192011-11-08 20:40:14 +02007058 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007059
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007060 bacpy(&ev.addr.bdaddr, bdaddr);
7061 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7062 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007063
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007064 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007065
7066 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007067 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007068
Johan Hedberg124f6e32012-02-09 13:50:12 +02007069 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007070 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007071}
7072
Marcel Holtmann78929242013-10-06 23:55:47 -07007073void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7074 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007075{
Andre Guedes3655bba2013-10-30 19:01:40 -03007076 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7077 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007078 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007079
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007080 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7081 hdev);
7082
Johan Hedberg333ae952015-03-17 13:48:47 +02007083 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007084 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007085 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007086
Andre Guedes3655bba2013-10-30 19:01:40 -03007087 cp = cmd->param;
7088
7089 if (bacmp(bdaddr, &cp->addr.bdaddr))
7090 return;
7091
7092 if (cp->addr.type != bdaddr_type)
7093 return;
7094
Johan Hedbergf5818c22014-12-05 13:36:02 +02007095 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007096 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007097}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007098
Marcel Holtmann445608d2013-10-06 23:55:48 -07007099void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7100 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007101{
7102 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007103
Johan Hedberg84c61d92014-08-01 11:13:30 +03007104 /* The connection is still in hci_conn_hash so test for 1
7105 * instead of 0 to know if this is the last one.
7106 */
7107 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7108 cancel_delayed_work(&hdev->power_off);
7109 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007110 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007111
Johan Hedberg4c659c32011-11-07 23:13:39 +02007112 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007113 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007114 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007115
Marcel Holtmann445608d2013-10-06 23:55:48 -07007116 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007117}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007118
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007119void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007120{
7121 struct mgmt_ev_pin_code_request ev;
7122
Johan Hedbergd8457692012-02-17 14:24:57 +02007123 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007124 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007125 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007126
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007127 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007128}
7129
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007130void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7131 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007132{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007133 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007134
Johan Hedberg333ae952015-03-17 13:48:47 +02007135 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007136 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007137 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007138
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007139 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007140 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007141}
7142
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007143void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7144 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007145{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007146 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007147
Johan Hedberg333ae952015-03-17 13:48:47 +02007148 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007149 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007150 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007151
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007152 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007153 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007154}
Johan Hedberga5c29682011-02-19 12:05:57 -03007155
Johan Hedberg744cf192011-11-08 20:40:14 +02007156int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007157 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007158 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007159{
7160 struct mgmt_ev_user_confirm_request ev;
7161
Johan Hedberg744cf192011-11-08 20:40:14 +02007162 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007163
Johan Hedberg272d90d2012-02-09 15:26:12 +02007164 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007165 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007166 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007167 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007168
Johan Hedberg744cf192011-11-08 20:40:14 +02007169 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007170 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007171}
7172
Johan Hedberg272d90d2012-02-09 15:26:12 +02007173int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007174 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007175{
7176 struct mgmt_ev_user_passkey_request ev;
7177
7178 BT_DBG("%s", hdev->name);
7179
Johan Hedberg272d90d2012-02-09 15:26:12 +02007180 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007181 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007182
7183 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007184 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007185}
7186
Brian Gix0df4c182011-11-16 13:53:13 -08007187static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007188 u8 link_type, u8 addr_type, u8 status,
7189 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007190{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007191 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007192
Johan Hedberg333ae952015-03-17 13:48:47 +02007193 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007194 if (!cmd)
7195 return -ENOENT;
7196
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007197 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007198 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007199
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007200 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007201}
7202
Johan Hedberg744cf192011-11-08 20:40:14 +02007203int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007204 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007205{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007206 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007207 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007208}
7209
Johan Hedberg272d90d2012-02-09 15:26:12 +02007210int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007211 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007212{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007213 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007214 status,
7215 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007216}
Johan Hedberg2a611692011-02-19 12:06:00 -03007217
Brian Gix604086b2011-11-23 08:28:33 -08007218int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007219 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007220{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007221 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007222 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007223}
7224
Johan Hedberg272d90d2012-02-09 15:26:12 +02007225int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007226 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007227{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007228 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007229 status,
7230 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007231}
7232
Johan Hedberg92a25252012-09-06 18:39:26 +03007233int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7234 u8 link_type, u8 addr_type, u32 passkey,
7235 u8 entered)
7236{
7237 struct mgmt_ev_passkey_notify ev;
7238
7239 BT_DBG("%s", hdev->name);
7240
7241 bacpy(&ev.addr.bdaddr, bdaddr);
7242 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7243 ev.passkey = __cpu_to_le32(passkey);
7244 ev.entered = entered;
7245
7246 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7247}
7248
Johan Hedberge1e930f2014-09-08 17:09:49 -07007249void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007250{
7251 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007252 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007253 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007254
Johan Hedberge1e930f2014-09-08 17:09:49 -07007255 bacpy(&ev.addr.bdaddr, &conn->dst);
7256 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7257 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007258
Johan Hedberge1e930f2014-09-08 17:09:49 -07007259 cmd = find_pairing(conn);
7260
7261 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7262 cmd ? cmd->sk : NULL);
7263
Johan Hedberga511b352014-12-11 21:45:45 +02007264 if (cmd) {
7265 cmd->cmd_complete(cmd, status);
7266 mgmt_pending_remove(cmd);
7267 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007268}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007269
Marcel Holtmann464996a2013-10-15 14:26:24 -07007270void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007271{
7272 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007273 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007274
7275 if (status) {
7276 u8 mgmt_err = mgmt_status(status);
7277 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007278 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007279 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007280 }
7281
Marcel Holtmann464996a2013-10-15 14:26:24 -07007282 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007283 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007284 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007285 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007286
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007287 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007288 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007289
Johan Hedberg47990ea2012-02-22 11:58:37 +02007290 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007291 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007292
7293 if (match.sk)
7294 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007295}
7296
Johan Hedberg890ea892013-03-15 17:06:52 -05007297static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007298{
Johan Hedberg890ea892013-03-15 17:06:52 -05007299 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007300 struct hci_cp_write_eir cp;
7301
Johan Hedberg976eb202012-10-24 21:12:01 +03007302 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007303 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007304
Johan Hedbergc80da272012-02-22 15:38:48 +02007305 memset(hdev->eir, 0, sizeof(hdev->eir));
7306
Johan Hedbergcacaf522012-02-21 00:52:42 +02007307 memset(&cp, 0, sizeof(cp));
7308
Johan Hedberg890ea892013-03-15 17:06:52 -05007309 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007310}
7311
Marcel Holtmann3e248562013-10-15 14:26:25 -07007312void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007313{
7314 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007315 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007316 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007317
7318 if (status) {
7319 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007320
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007321 if (enable && hci_dev_test_and_clear_flag(hdev,
7322 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007323 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007324 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007325 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007326
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007327 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7328 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007329 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007330 }
7331
7332 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007333 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007334 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007335 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007336 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007337 changed = hci_dev_test_and_clear_flag(hdev,
7338 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007339 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007340 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007341 }
7342
7343 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7344
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007345 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007346 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007347
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007348 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007349 sock_put(match.sk);
7350
Johan Hedberg890ea892013-03-15 17:06:52 -05007351 hci_req_init(&req, hdev);
7352
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007353 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7354 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007355 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7356 sizeof(enable), &enable);
Johan Hedberg890ea892013-03-15 17:06:52 -05007357 update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007358 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007359 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007360 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007361
7362 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007363}
7364
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007365static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007366{
7367 struct cmd_lookup *match = data;
7368
Johan Hedberg90e70452012-02-23 23:09:40 +02007369 if (match->sk == NULL) {
7370 match->sk = cmd->sk;
7371 sock_hold(match->sk);
7372 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007373}
7374
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007375void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7376 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007377{
Johan Hedberg90e70452012-02-23 23:09:40 +02007378 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007379
Johan Hedberg92da6092013-03-15 17:06:55 -05007380 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7381 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7382 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007383
7384 if (!status)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007385 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7386 dev_class, 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02007387
7388 if (match.sk)
7389 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007390}
7391
Marcel Holtmann7667da32013-10-15 14:26:27 -07007392void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007393{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007394 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007395 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007396
Johan Hedberg13928972013-03-15 17:07:00 -05007397 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007398 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007399
7400 memset(&ev, 0, sizeof(ev));
7401 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007402 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007403
Johan Hedberg333ae952015-03-17 13:48:47 +02007404 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007405 if (!cmd) {
7406 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007407
Johan Hedberg13928972013-03-15 17:07:00 -05007408 /* If this is a HCI command related to powering on the
7409 * HCI dev don't send any mgmt signals.
7410 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007411 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007412 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007413 }
7414
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007415 mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7416 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007417}
Szymon Jancc35938b2011-03-22 13:12:21 +01007418
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007419void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
Johan Hedberg38da1702014-11-17 20:52:20 +02007420 u8 *rand192, u8 *hash256, u8 *rand256,
7421 u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01007422{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007423 struct mgmt_pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01007424
Johan Hedberg744cf192011-11-08 20:40:14 +02007425 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01007426
Johan Hedberg333ae952015-03-17 13:48:47 +02007427 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01007428 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07007429 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01007430
7431 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02007432 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
7433 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01007434 } else {
Johan Hedberg66f096f2015-02-02 13:23:42 +02007435 struct mgmt_rp_read_local_oob_data rp;
7436 size_t rp_size = sizeof(rp);
7437
7438 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
7439 memcpy(rp.rand192, rand192, sizeof(rp.rand192));
7440
Johan Hedberg710f11c2014-05-26 11:21:22 +03007441 if (bredr_sc_enabled(hdev) && hash256 && rand256) {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007442 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
Johan Hedberg38da1702014-11-17 20:52:20 +02007443 memcpy(rp.rand256, rand256, sizeof(rp.rand256));
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007444 } else {
Johan Hedberg66f096f2015-02-02 13:23:42 +02007445 rp_size -= sizeof(rp.hash256) + sizeof(rp.rand256);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007446 }
Johan Hedberg66f096f2015-02-02 13:23:42 +02007447
Johan Hedberg2a1afb52015-03-06 21:08:54 +02007448 mgmt_cmd_complete(cmd->sk, hdev->id,
7449 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
7450 &rp, rp_size);
Szymon Jancc35938b2011-03-22 13:12:21 +01007451 }
7452
7453 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01007454}
Johan Hedberge17acd42011-03-30 23:57:16 +03007455
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007456static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7457{
7458 int i;
7459
7460 for (i = 0; i < uuid_count; i++) {
7461 if (!memcmp(uuid, uuids[i], 16))
7462 return true;
7463 }
7464
7465 return false;
7466}
7467
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007468static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7469{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007470 u16 parsed = 0;
7471
7472 while (parsed < eir_len) {
7473 u8 field_len = eir[0];
7474 u8 uuid[16];
7475 int i;
7476
7477 if (field_len == 0)
7478 break;
7479
7480 if (eir_len - parsed < field_len + 1)
7481 break;
7482
7483 switch (eir[1]) {
7484 case EIR_UUID16_ALL:
7485 case EIR_UUID16_SOME:
7486 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007487 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007488 uuid[13] = eir[i + 3];
7489 uuid[12] = eir[i + 2];
7490 if (has_uuid(uuid, uuid_count, uuids))
7491 return true;
7492 }
7493 break;
7494 case EIR_UUID32_ALL:
7495 case EIR_UUID32_SOME:
7496 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007497 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007498 uuid[15] = eir[i + 5];
7499 uuid[14] = eir[i + 4];
7500 uuid[13] = eir[i + 3];
7501 uuid[12] = eir[i + 2];
7502 if (has_uuid(uuid, uuid_count, uuids))
7503 return true;
7504 }
7505 break;
7506 case EIR_UUID128_ALL:
7507 case EIR_UUID128_SOME:
7508 for (i = 0; i + 17 <= field_len; i += 16) {
7509 memcpy(uuid, eir + i + 2, 16);
7510 if (has_uuid(uuid, uuid_count, uuids))
7511 return true;
7512 }
7513 break;
7514 }
7515
7516 parsed += field_len + 1;
7517 eir += field_len + 1;
7518 }
7519
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007520 return false;
7521}
7522
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007523static void restart_le_scan(struct hci_dev *hdev)
7524{
7525 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007526 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007527 return;
7528
7529 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7530 hdev->discovery.scan_start +
7531 hdev->discovery.scan_duration))
7532 return;
7533
7534 queue_delayed_work(hdev->workqueue, &hdev->le_scan_restart,
7535 DISCOV_LE_RESTART_DELAY);
7536}
7537
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007538static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7539 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7540{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007541 /* If a RSSI threshold has been specified, and
7542 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7543 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7544 * is set, let it through for further processing, as we might need to
7545 * restart the scan.
7546 *
7547 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7548 * the results are also dropped.
7549 */
7550 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7551 (rssi == HCI_RSSI_INVALID ||
7552 (rssi < hdev->discovery.rssi &&
7553 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7554 return false;
7555
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007556 if (hdev->discovery.uuid_count != 0) {
7557 /* If a list of UUIDs is provided in filter, results with no
7558 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007559 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007560 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7561 hdev->discovery.uuids) &&
7562 !eir_has_uuids(scan_rsp, scan_rsp_len,
7563 hdev->discovery.uuid_count,
7564 hdev->discovery.uuids))
7565 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007566 }
7567
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007568 /* If duplicate filtering does not report RSSI changes, then restart
7569 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007570 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007571 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7572 restart_le_scan(hdev);
7573
7574 /* Validate RSSI value against the RSSI threshold once more. */
7575 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7576 rssi < hdev->discovery.rssi)
7577 return false;
7578 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007579
7580 return true;
7581}
7582
Marcel Holtmann901801b2013-10-06 23:55:51 -07007583void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007584 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7585 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007586{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007587 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007588 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007589 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007590
Johan Hedberg75ce2082014-07-02 22:42:01 +03007591 /* Don't send events for a non-kernel initiated discovery. With
7592 * LE one exception is if we have pend_le_reports > 0 in which
7593 * case we're doing passive scanning and want these events.
7594 */
7595 if (!hci_discovery_active(hdev)) {
7596 if (link_type == ACL_LINK)
7597 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007598 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007599 return;
7600 }
Andre Guedes12602d02013-04-30 15:29:40 -03007601
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007602 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007603 /* We are using service discovery */
7604 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7605 scan_rsp_len))
7606 return;
7607 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007608
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007609 /* Make sure that the buffer is big enough. The 5 extra bytes
7610 * are for the potential CoD field.
7611 */
7612 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007613 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007614
Johan Hedberg1dc06092012-01-15 21:01:23 +02007615 memset(buf, 0, sizeof(buf));
7616
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007617 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7618 * RSSI value was reported as 0 when not available. This behavior
7619 * is kept when using device discovery. This is required for full
7620 * backwards compatibility with the API.
7621 *
7622 * However when using service discovery, the value 127 will be
7623 * returned when the RSSI is not available.
7624 */
Szymon Janc91200e92015-01-22 16:57:05 +01007625 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7626 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007627 rssi = 0;
7628
Johan Hedberg841c5642014-07-07 12:45:54 +03007629 bacpy(&ev->addr.bdaddr, bdaddr);
7630 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007631 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007632 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007633
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007634 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007635 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007636 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007637
Johan Hedberg1dc06092012-01-15 21:01:23 +02007638 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
7639 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007640 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007641
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007642 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007643 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007644 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007645
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007646 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7647 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007648
Marcel Holtmann901801b2013-10-06 23:55:51 -07007649 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007650}
Johan Hedberga88a9652011-03-30 13:18:12 +03007651
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007652void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7653 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007654{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007655 struct mgmt_ev_device_found *ev;
7656 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7657 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007658
Johan Hedbergb644ba32012-01-17 21:48:47 +02007659 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007660
Johan Hedbergb644ba32012-01-17 21:48:47 +02007661 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007662
Johan Hedbergb644ba32012-01-17 21:48:47 +02007663 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007664 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007665 ev->rssi = rssi;
7666
7667 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007668 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007669
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007670 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007671
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007672 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007673}
Johan Hedberg314b2382011-04-27 10:29:57 -04007674
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007675void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007676{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007677 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007678
Andre Guedes343fb142011-11-22 17:14:19 -03007679 BT_DBG("%s discovering %u", hdev->name, discovering);
7680
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007681 memset(&ev, 0, sizeof(ev));
7682 ev.type = hdev->discovery.type;
7683 ev.discovering = discovering;
7684
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007685 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007686}
Antti Julku5e762442011-08-25 16:48:02 +03007687
Marcel Holtmann1904a852015-01-11 13:50:44 -08007688static void adv_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Marcel Holtmann5976e602013-10-06 04:08:14 -07007689{
7690 BT_DBG("%s status %u", hdev->name, status);
Marcel Holtmann5976e602013-10-06 04:08:14 -07007691}
7692
7693void mgmt_reenable_advertising(struct hci_dev *hdev)
7694{
7695 struct hci_request req;
7696
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007697 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Marcel Holtmann5976e602013-10-06 04:08:14 -07007698 return;
7699
7700 hci_req_init(&req, hdev);
7701 enable_advertising(&req);
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03007702 hci_req_run(&req, adv_enable_complete);
Marcel Holtmann5976e602013-10-06 04:08:14 -07007703}
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007704
7705static struct hci_mgmt_chan chan = {
7706 .channel = HCI_CHANNEL_CONTROL,
7707 .handler_count = ARRAY_SIZE(mgmt_handlers),
7708 .handlers = mgmt_handlers,
7709};
7710
7711int mgmt_init(void)
7712{
7713 return hci_mgmt_chan_register(&chan);
7714}
7715
7716void mgmt_exit(void)
7717{
7718 hci_mgmt_chan_unregister(&chan);
7719}