blob: aa233e37fc934a84cf2e9f4e7c7c7b1551ebdef4 [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 Hedberg03811012010-12-08 00:21:06 +020038
Johan Hedberg2da9c552012-02-17 14:39:28 +020039#define MGMT_VERSION 1
Marcel Holtmannbeb1c212015-03-10 14:04:52 -070040#define MGMT_REVISION 9
Johan Hedberg02d98122010-12-13 21:07:04 +020041
Johan Hedberge70bb2e2012-02-13 16:59:33 +020042static const u16 mgmt_commands[] = {
43 MGMT_OP_READ_INDEX_LIST,
44 MGMT_OP_READ_INFO,
45 MGMT_OP_SET_POWERED,
46 MGMT_OP_SET_DISCOVERABLE,
47 MGMT_OP_SET_CONNECTABLE,
48 MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergb2939472014-07-30 09:22:23 +030049 MGMT_OP_SET_BONDABLE,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020050 MGMT_OP_SET_LINK_SECURITY,
51 MGMT_OP_SET_SSP,
52 MGMT_OP_SET_HS,
53 MGMT_OP_SET_LE,
54 MGMT_OP_SET_DEV_CLASS,
55 MGMT_OP_SET_LOCAL_NAME,
56 MGMT_OP_ADD_UUID,
57 MGMT_OP_REMOVE_UUID,
58 MGMT_OP_LOAD_LINK_KEYS,
59 MGMT_OP_LOAD_LONG_TERM_KEYS,
60 MGMT_OP_DISCONNECT,
61 MGMT_OP_GET_CONNECTIONS,
62 MGMT_OP_PIN_CODE_REPLY,
63 MGMT_OP_PIN_CODE_NEG_REPLY,
64 MGMT_OP_SET_IO_CAPABILITY,
65 MGMT_OP_PAIR_DEVICE,
66 MGMT_OP_CANCEL_PAIR_DEVICE,
67 MGMT_OP_UNPAIR_DEVICE,
68 MGMT_OP_USER_CONFIRM_REPLY,
69 MGMT_OP_USER_CONFIRM_NEG_REPLY,
70 MGMT_OP_USER_PASSKEY_REPLY,
71 MGMT_OP_USER_PASSKEY_NEG_REPLY,
72 MGMT_OP_READ_LOCAL_OOB_DATA,
73 MGMT_OP_ADD_REMOTE_OOB_DATA,
74 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
75 MGMT_OP_START_DISCOVERY,
76 MGMT_OP_STOP_DISCOVERY,
77 MGMT_OP_CONFIRM_NAME,
78 MGMT_OP_BLOCK_DEVICE,
79 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070080 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030081 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030082 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070083 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070084 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080085 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080086 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg62b04cd2014-02-23 19:42:27 +020087 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020088 MGMT_OP_LOAD_IRKS,
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +020089 MGMT_OP_GET_CONN_INFO,
Johan Hedberg95868422014-06-28 17:54:07 +030090 MGMT_OP_GET_CLOCK_INFO,
Marcel Holtmann2faade52014-06-29 19:44:03 +020091 MGMT_OP_ADD_DEVICE,
92 MGMT_OP_REMOVE_DEVICE,
Johan Hedberga26f3dc2014-07-02 17:37:29 +030093 MGMT_OP_LOAD_CONN_PARAM,
Marcel Holtmann73d1df22014-07-02 22:10:52 +020094 MGMT_OP_READ_UNCONF_INDEX_LIST,
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +020095 MGMT_OP_READ_CONFIG_INFO,
Marcel Holtmanndbece372014-07-04 18:11:55 +020096 MGMT_OP_SET_EXTERNAL_CONFIG,
Marcel Holtmann9713c172014-07-06 12:11:15 +020097 MGMT_OP_SET_PUBLIC_ADDRESS,
Jakub Pawlowski66ea9422014-12-05 10:55:59 +010098 MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020099};
100
101static const u16 mgmt_events[] = {
102 MGMT_EV_CONTROLLER_ERROR,
103 MGMT_EV_INDEX_ADDED,
104 MGMT_EV_INDEX_REMOVED,
105 MGMT_EV_NEW_SETTINGS,
106 MGMT_EV_CLASS_OF_DEV_CHANGED,
107 MGMT_EV_LOCAL_NAME_CHANGED,
108 MGMT_EV_NEW_LINK_KEY,
109 MGMT_EV_NEW_LONG_TERM_KEY,
110 MGMT_EV_DEVICE_CONNECTED,
111 MGMT_EV_DEVICE_DISCONNECTED,
112 MGMT_EV_CONNECT_FAILED,
113 MGMT_EV_PIN_CODE_REQUEST,
114 MGMT_EV_USER_CONFIRM_REQUEST,
115 MGMT_EV_USER_PASSKEY_REQUEST,
116 MGMT_EV_AUTH_FAILED,
117 MGMT_EV_DEVICE_FOUND,
118 MGMT_EV_DISCOVERING,
119 MGMT_EV_DEVICE_BLOCKED,
120 MGMT_EV_DEVICE_UNBLOCKED,
121 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300122 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800123 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700124 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200125 MGMT_EV_DEVICE_ADDED,
126 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300127 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200128 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd38962014-07-02 21:30:55 +0200129 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200130 MGMT_EV_NEW_CONFIG_OPTIONS,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200131};
132
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800133#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200134
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200135#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
136 "\x00\x00\x00\x00\x00\x00\x00\x00"
137
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200138struct mgmt_pending_cmd {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200139 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200140 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200141 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100142 void *param;
Johan Hedberg323b0b82014-12-05 13:36:01 +0200143 size_t param_len;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200144 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300145 void *user_data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200146 int (*cmd_complete)(struct mgmt_pending_cmd *cmd, u8 status);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200147};
148
Johan Hedbergca69b792011-11-11 18:10:00 +0200149/* HCI to MGMT error code conversion table */
150static u8 mgmt_status_table[] = {
151 MGMT_STATUS_SUCCESS,
152 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
153 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
154 MGMT_STATUS_FAILED, /* Hardware Failure */
155 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
156 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200157 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200158 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
159 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
160 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
161 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
162 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
163 MGMT_STATUS_BUSY, /* Command Disallowed */
164 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
165 MGMT_STATUS_REJECTED, /* Rejected Security */
166 MGMT_STATUS_REJECTED, /* Rejected Personal */
167 MGMT_STATUS_TIMEOUT, /* Host Timeout */
168 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
169 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
170 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
171 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
172 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
173 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
174 MGMT_STATUS_BUSY, /* Repeated Attempts */
175 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
176 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
177 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
178 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
179 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
180 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
181 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
182 MGMT_STATUS_FAILED, /* Unspecified Error */
183 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
184 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
185 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
186 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
187 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
188 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
189 MGMT_STATUS_FAILED, /* Unit Link Key Used */
190 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
191 MGMT_STATUS_TIMEOUT, /* Instant Passed */
192 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
193 MGMT_STATUS_FAILED, /* Transaction Collision */
194 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
195 MGMT_STATUS_REJECTED, /* QoS Rejected */
196 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
197 MGMT_STATUS_REJECTED, /* Insufficient Security */
198 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
199 MGMT_STATUS_BUSY, /* Role Switch Pending */
200 MGMT_STATUS_FAILED, /* Slot Violation */
201 MGMT_STATUS_FAILED, /* Role Switch Failed */
202 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
203 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
204 MGMT_STATUS_BUSY, /* Host Busy Pairing */
205 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
206 MGMT_STATUS_BUSY, /* Controller Busy */
207 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
208 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
209 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
210 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
211 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
212};
213
214static u8 mgmt_status(u8 hci_status)
215{
216 if (hci_status < ARRAY_SIZE(mgmt_status_table))
217 return mgmt_status_table[hci_status];
218
219 return MGMT_STATUS_FAILED;
220}
221
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200222static int mgmt_send_event(u16 event, struct hci_dev *hdev,
223 unsigned short channel, void *data, u16 data_len,
224 struct sock *skip_sk)
Marcel Holtmann04c60f052014-07-04 19:06:22 +0200225{
226 struct sk_buff *skb;
227 struct mgmt_hdr *hdr;
228
229 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
230 if (!skb)
231 return -ENOMEM;
232
233 hdr = (void *) skb_put(skb, sizeof(*hdr));
234 hdr->opcode = cpu_to_le16(event);
235 if (hdev)
236 hdr->index = cpu_to_le16(hdev->id);
237 else
238 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
239 hdr->len = cpu_to_le16(data_len);
240
241 if (data)
242 memcpy(skb_put(skb, data_len), data, data_len);
243
244 /* Time stamp */
245 __net_timestamp(skb);
246
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200247 hci_send_to_channel(channel, skb, skip_sk);
Marcel Holtmann04c60f052014-07-04 19:06:22 +0200248 kfree_skb(skb);
249
250 return 0;
251}
252
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200253static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
254 struct sock *skip_sk)
255{
256 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
257 skip_sk);
258}
259
Johan Hedberga69e8372015-03-06 21:08:53 +0200260static int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200261{
262 struct sk_buff *skb;
263 struct mgmt_hdr *hdr;
264 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300265 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200266
Szymon Janc34eb5252011-02-28 14:10:08 +0100267 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200268
Andre Guedes790eff42012-06-07 19:05:46 -0300269 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200270 if (!skb)
271 return -ENOMEM;
272
273 hdr = (void *) skb_put(skb, sizeof(*hdr));
274
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700275 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100276 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200277 hdr->len = cpu_to_le16(sizeof(*ev));
278
279 ev = (void *) skb_put(skb, sizeof(*ev));
280 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200281 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200282
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300283 err = sock_queue_rcv_skb(sk, skb);
284 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200285 kfree_skb(skb);
286
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300287 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200288}
289
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200290static int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
291 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200292{
293 struct sk_buff *skb;
294 struct mgmt_hdr *hdr;
295 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300296 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200297
298 BT_DBG("sock %p", sk);
299
Andre Guedes790eff42012-06-07 19:05:46 -0300300 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200301 if (!skb)
302 return -ENOMEM;
303
304 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200305
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700306 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100307 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200308 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200309
Johan Hedberga38528f2011-01-22 06:46:43 +0200310 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200311 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200312 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100313
314 if (rp)
315 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200316
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300317 err = sock_queue_rcv_skb(sk, skb);
318 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200319 kfree_skb(skb);
320
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100321 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200322}
323
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300324static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
325 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200326{
327 struct mgmt_rp_read_version rp;
328
329 BT_DBG("sock %p", sk);
330
331 rp.version = MGMT_VERSION;
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700332 rp.revision = cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200333
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200334 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
335 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200336}
337
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300338static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
339 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200340{
341 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200342 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
343 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200344 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200345 size_t rp_size;
346 int i, err;
347
348 BT_DBG("sock %p", sk);
349
350 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
351
352 rp = kmalloc(rp_size, GFP_KERNEL);
353 if (!rp)
354 return -ENOMEM;
355
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700356 rp->num_commands = cpu_to_le16(num_commands);
357 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200358
359 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
360 put_unaligned_le16(mgmt_commands[i], opcode);
361
362 for (i = 0; i < num_events; i++, opcode++)
363 put_unaligned_le16(mgmt_events[i], opcode);
364
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200365 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
366 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200367 kfree(rp);
368
369 return err;
370}
371
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300372static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
373 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200374{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200375 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200376 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200377 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200378 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300379 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200380
381 BT_DBG("sock %p", sk);
382
383 read_lock(&hci_dev_list_lock);
384
385 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300386 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200387 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700388 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700389 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200390 }
391
Johan Hedberga38528f2011-01-22 06:46:43 +0200392 rp_len = sizeof(*rp) + (2 * count);
393 rp = kmalloc(rp_len, GFP_ATOMIC);
394 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100395 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200396 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100397 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200398
Johan Hedberg476e44c2012-10-19 20:10:46 +0300399 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200400 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700401 if (hci_dev_test_flag(d, HCI_SETUP) ||
402 hci_dev_test_flag(d, HCI_CONFIG) ||
403 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200404 continue;
405
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200406 /* Devices marked as raw-only are neither configured
407 * nor unconfigured controllers.
408 */
409 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700410 continue;
411
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200412 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700413 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700414 rp->index[count++] = cpu_to_le16(d->id);
415 BT_DBG("Added hci%u", d->id);
416 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200417 }
418
Johan Hedberg476e44c2012-10-19 20:10:46 +0300419 rp->num_controllers = cpu_to_le16(count);
420 rp_len = sizeof(*rp) + (2 * count);
421
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200422 read_unlock(&hci_dev_list_lock);
423
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200424 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
425 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200426
Johan Hedberga38528f2011-01-22 06:46:43 +0200427 kfree(rp);
428
429 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200430}
431
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200432static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
433 void *data, u16 data_len)
434{
435 struct mgmt_rp_read_unconf_index_list *rp;
436 struct hci_dev *d;
437 size_t rp_len;
438 u16 count;
439 int err;
440
441 BT_DBG("sock %p", sk);
442
443 read_lock(&hci_dev_list_lock);
444
445 count = 0;
446 list_for_each_entry(d, &hci_dev_list, list) {
447 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700448 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200449 count++;
450 }
451
452 rp_len = sizeof(*rp) + (2 * count);
453 rp = kmalloc(rp_len, GFP_ATOMIC);
454 if (!rp) {
455 read_unlock(&hci_dev_list_lock);
456 return -ENOMEM;
457 }
458
459 count = 0;
460 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700461 if (hci_dev_test_flag(d, HCI_SETUP) ||
462 hci_dev_test_flag(d, HCI_CONFIG) ||
463 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200464 continue;
465
466 /* Devices marked as raw-only are neither configured
467 * nor unconfigured controllers.
468 */
469 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
470 continue;
471
472 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700473 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200474 rp->index[count++] = cpu_to_le16(d->id);
475 BT_DBG("Added hci%u", d->id);
476 }
477 }
478
479 rp->num_controllers = cpu_to_le16(count);
480 rp_len = sizeof(*rp) + (2 * count);
481
482 read_unlock(&hci_dev_list_lock);
483
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200484 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
485 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200486
487 kfree(rp);
488
489 return err;
490}
491
Marcel Holtmanndbece372014-07-04 18:11:55 +0200492static bool is_configured(struct hci_dev *hdev)
493{
494 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700495 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200496 return false;
497
498 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
499 !bacmp(&hdev->public_addr, BDADDR_ANY))
500 return false;
501
502 return true;
503}
504
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200505static __le32 get_missing_options(struct hci_dev *hdev)
506{
507 u32 options = 0;
508
Marcel Holtmanndbece372014-07-04 18:11:55 +0200509 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700510 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200511 options |= MGMT_OPTION_EXTERNAL_CONFIG;
512
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200513 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
514 !bacmp(&hdev->public_addr, BDADDR_ANY))
515 options |= MGMT_OPTION_PUBLIC_ADDRESS;
516
517 return cpu_to_le32(options);
518}
519
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200520static int new_options(struct hci_dev *hdev, struct sock *skip)
521{
522 __le32 options = get_missing_options(hdev);
523
524 return mgmt_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
525 sizeof(options), skip);
526}
527
Marcel Holtmanndbece372014-07-04 18:11:55 +0200528static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
529{
530 __le32 options = get_missing_options(hdev);
531
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200532 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
533 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200534}
535
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200536static int read_config_info(struct sock *sk, struct hci_dev *hdev,
537 void *data, u16 data_len)
538{
539 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200540 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200541
542 BT_DBG("sock %p %s", sk, hdev->name);
543
544 hci_dev_lock(hdev);
545
546 memset(&rp, 0, sizeof(rp));
547 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200548
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200549 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
550 options |= MGMT_OPTION_EXTERNAL_CONFIG;
551
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200552 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200553 options |= MGMT_OPTION_PUBLIC_ADDRESS;
554
555 rp.supported_options = cpu_to_le32(options);
556 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200557
558 hci_dev_unlock(hdev);
559
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200560 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
561 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200562}
563
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200564static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200565{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200566 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200567
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200568 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300569 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800570 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300571 settings |= MGMT_SETTING_CONNECTABLE;
572 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200573
Andre Guedesed3fa312012-07-24 15:03:46 -0300574 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500575 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
576 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200577 settings |= MGMT_SETTING_BREDR;
578 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700579
580 if (lmp_ssp_capable(hdev)) {
581 settings |= MGMT_SETTING_SSP;
582 settings |= MGMT_SETTING_HS;
583 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800584
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800585 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800586 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700587 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100588
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300589 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200590 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300591 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300592 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200593 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800594 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300595 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200596
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200597 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
598 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200599 settings |= MGMT_SETTING_CONFIGURATION;
600
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200601 return settings;
602}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200603
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200604static u32 get_current_settings(struct hci_dev *hdev)
605{
606 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200607
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200608 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100609 settings |= MGMT_SETTING_POWERED;
610
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700611 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200612 settings |= MGMT_SETTING_CONNECTABLE;
613
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700614 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500615 settings |= MGMT_SETTING_FAST_CONNECTABLE;
616
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700617 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200618 settings |= MGMT_SETTING_DISCOVERABLE;
619
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700620 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300621 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200622
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700623 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200624 settings |= MGMT_SETTING_BREDR;
625
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700626 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200627 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200628
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700629 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200630 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200631
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700632 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200633 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200634
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700635 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200636 settings |= MGMT_SETTING_HS;
637
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700638 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300639 settings |= MGMT_SETTING_ADVERTISING;
640
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700641 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800642 settings |= MGMT_SETTING_SECURE_CONN;
643
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700644 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800645 settings |= MGMT_SETTING_DEBUG_KEYS;
646
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700647 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200648 settings |= MGMT_SETTING_PRIVACY;
649
Marcel Holtmann93690c22015-03-06 10:11:21 -0800650 /* The current setting for static address has two purposes. The
651 * first is to indicate if the static address will be used and
652 * the second is to indicate if it is actually set.
653 *
654 * This means if the static address is not configured, this flag
655 * will never bet set. If the address is configured, then if the
656 * address is actually used decides if the flag is set or not.
657 *
658 * For single mode LE only controllers and dual-mode controllers
659 * with BR/EDR disabled, the existence of the static address will
660 * be evaluated.
661 */
662 if (test_bit(HCI_FORCE_STATIC_ADDR, &hdev->dbg_flags) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700663 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800664 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
665 if (bacmp(&hdev->static_addr, BDADDR_ANY))
666 settings |= MGMT_SETTING_STATIC_ADDRESS;
667 }
668
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200669 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200670}
671
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300672#define PNP_INFO_SVCLASS_ID 0x1200
673
Johan Hedberg213202e2013-01-27 00:31:33 +0200674static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
675{
676 u8 *ptr = data, *uuids_start = NULL;
677 struct bt_uuid *uuid;
678
679 if (len < 4)
680 return ptr;
681
682 list_for_each_entry(uuid, &hdev->uuids, list) {
683 u16 uuid16;
684
685 if (uuid->size != 16)
686 continue;
687
688 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
689 if (uuid16 < 0x1100)
690 continue;
691
692 if (uuid16 == PNP_INFO_SVCLASS_ID)
693 continue;
694
695 if (!uuids_start) {
696 uuids_start = ptr;
697 uuids_start[0] = 1;
698 uuids_start[1] = EIR_UUID16_ALL;
699 ptr += 2;
700 }
701
702 /* Stop if not enough space to put next UUID */
703 if ((ptr - data) + sizeof(u16) > len) {
704 uuids_start[1] = EIR_UUID16_SOME;
705 break;
706 }
707
708 *ptr++ = (uuid16 & 0x00ff);
709 *ptr++ = (uuid16 & 0xff00) >> 8;
710 uuids_start[0] += sizeof(uuid16);
711 }
712
713 return ptr;
714}
715
Johan Hedbergcdf19632013-01-27 00:31:34 +0200716static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
717{
718 u8 *ptr = data, *uuids_start = NULL;
719 struct bt_uuid *uuid;
720
721 if (len < 6)
722 return ptr;
723
724 list_for_each_entry(uuid, &hdev->uuids, list) {
725 if (uuid->size != 32)
726 continue;
727
728 if (!uuids_start) {
729 uuids_start = ptr;
730 uuids_start[0] = 1;
731 uuids_start[1] = EIR_UUID32_ALL;
732 ptr += 2;
733 }
734
735 /* Stop if not enough space to put next UUID */
736 if ((ptr - data) + sizeof(u32) > len) {
737 uuids_start[1] = EIR_UUID32_SOME;
738 break;
739 }
740
741 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
742 ptr += sizeof(u32);
743 uuids_start[0] += sizeof(u32);
744 }
745
746 return ptr;
747}
748
Johan Hedbergc00d5752013-01-27 00:31:35 +0200749static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
750{
751 u8 *ptr = data, *uuids_start = NULL;
752 struct bt_uuid *uuid;
753
754 if (len < 18)
755 return ptr;
756
757 list_for_each_entry(uuid, &hdev->uuids, list) {
758 if (uuid->size != 128)
759 continue;
760
761 if (!uuids_start) {
762 uuids_start = ptr;
763 uuids_start[0] = 1;
764 uuids_start[1] = EIR_UUID128_ALL;
765 ptr += 2;
766 }
767
768 /* Stop if not enough space to put next UUID */
769 if ((ptr - data) + 16 > len) {
770 uuids_start[1] = EIR_UUID128_SOME;
771 break;
772 }
773
774 memcpy(ptr, uuid->uuid, 16);
775 ptr += 16;
776 uuids_start[0] += 16;
777 }
778
779 return ptr;
780}
781
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200782static struct mgmt_pending_cmd *mgmt_pending_find(u16 opcode,
783 struct hci_dev *hdev)
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300784{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200785 struct mgmt_pending_cmd *cmd;
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300786
787 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
788 if (cmd->opcode == opcode)
789 return cmd;
790 }
791
792 return NULL;
793}
794
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200795static struct mgmt_pending_cmd *mgmt_pending_find_data(u16 opcode,
796 struct hci_dev *hdev,
797 const void *data)
Johan Hedberg95868422014-06-28 17:54:07 +0300798{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200799 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +0300800
801 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
802 if (cmd->user_data != data)
803 continue;
804 if (cmd->opcode == opcode)
805 return cmd;
806 }
807
808 return NULL;
809}
810
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700811static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
812{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700813 u8 ad_len = 0;
814 size_t name_len;
815
816 name_len = strlen(hdev->dev_name);
817 if (name_len > 0) {
818 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
819
820 if (name_len > max_len) {
821 name_len = max_len;
822 ptr[1] = EIR_NAME_SHORT;
823 } else
824 ptr[1] = EIR_NAME_COMPLETE;
825
826 ptr[0] = name_len + 1;
827
828 memcpy(ptr + 2, hdev->dev_name, name_len);
829
830 ad_len += (name_len + 2);
831 ptr += (name_len + 2);
832 }
833
834 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700835}
836
837static void update_scan_rsp_data(struct hci_request *req)
838{
839 struct hci_dev *hdev = req->hdev;
840 struct hci_cp_le_set_scan_rsp_data cp;
841 u8 len;
842
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700843 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700844 return;
845
846 memset(&cp, 0, sizeof(cp));
847
848 len = create_scan_rsp_data(hdev, cp.data);
849
Johan Hedbergeb438b52013-10-16 15:31:07 +0300850 if (hdev->scan_rsp_data_len == len &&
851 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700852 return;
853
Johan Hedbergeb438b52013-10-16 15:31:07 +0300854 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
855 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700856
857 cp.length = len;
858
859 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
860}
861
Johan Hedberg9a43e252013-10-20 19:00:07 +0300862static u8 get_adv_discov_flags(struct hci_dev *hdev)
863{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200864 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300865
866 /* If there's a pending mgmt command the flags will not yet have
867 * their final values, so check for this first.
868 */
869 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
870 if (cmd) {
871 struct mgmt_mode *cp = cmd->param;
872 if (cp->val == 0x01)
873 return LE_AD_GENERAL;
874 else if (cp->val == 0x02)
875 return LE_AD_LIMITED;
876 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700877 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300878 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700879 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300880 return LE_AD_GENERAL;
881 }
882
883 return 0;
884}
885
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700886static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700887{
888 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700889
Johan Hedberg9a43e252013-10-20 19:00:07 +0300890 flags |= get_adv_discov_flags(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700891
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700892 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700893 flags |= LE_AD_NO_BREDR;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700894
895 if (flags) {
896 BT_DBG("adv flags 0x%02x", flags);
897
898 ptr[0] = 2;
899 ptr[1] = EIR_FLAGS;
900 ptr[2] = flags;
901
902 ad_len += 3;
903 ptr += 3;
904 }
905
906 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
907 ptr[0] = 2;
908 ptr[1] = EIR_TX_POWER;
909 ptr[2] = (u8) hdev->adv_tx_power;
910
911 ad_len += 3;
912 ptr += 3;
913 }
914
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700915 return ad_len;
916}
917
Marcel Holtmann5947f4b2013-10-16 00:16:50 -0700918static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700919{
920 struct hci_dev *hdev = req->hdev;
921 struct hci_cp_le_set_adv_data cp;
922 u8 len;
923
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700924 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700925 return;
926
927 memset(&cp, 0, sizeof(cp));
928
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700929 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700930
931 if (hdev->adv_data_len == len &&
932 memcmp(cp.data, hdev->adv_data, len) == 0)
933 return;
934
935 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
936 hdev->adv_data_len = len;
937
938 cp.length = len;
939
940 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
941}
942
Johan Hedbergbc6d2d02014-07-10 12:09:08 +0300943int mgmt_update_adv_data(struct hci_dev *hdev)
944{
945 struct hci_request req;
946
947 hci_req_init(&req, hdev);
948 update_adv_data(&req);
949
950 return hci_req_run(&req, NULL);
951}
952
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300953static void create_eir(struct hci_dev *hdev, u8 *data)
954{
955 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300956 size_t name_len;
957
958 name_len = strlen(hdev->dev_name);
959
960 if (name_len > 0) {
961 /* EIR Data type */
962 if (name_len > 48) {
963 name_len = 48;
964 ptr[1] = EIR_NAME_SHORT;
965 } else
966 ptr[1] = EIR_NAME_COMPLETE;
967
968 /* EIR Data length */
969 ptr[0] = name_len + 1;
970
971 memcpy(ptr + 2, hdev->dev_name, name_len);
972
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300973 ptr += (name_len + 2);
974 }
975
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100976 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700977 ptr[0] = 2;
978 ptr[1] = EIR_TX_POWER;
979 ptr[2] = (u8) hdev->inq_tx_power;
980
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700981 ptr += 3;
982 }
983
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700984 if (hdev->devid_source > 0) {
985 ptr[0] = 9;
986 ptr[1] = EIR_DEVICE_ID;
987
988 put_unaligned_le16(hdev->devid_source, ptr + 2);
989 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
990 put_unaligned_le16(hdev->devid_product, ptr + 6);
991 put_unaligned_le16(hdev->devid_version, ptr + 8);
992
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700993 ptr += 10;
994 }
995
Johan Hedberg213202e2013-01-27 00:31:33 +0200996 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200997 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200998 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300999}
1000
Johan Hedberg890ea892013-03-15 17:06:52 -05001001static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001002{
Johan Hedberg890ea892013-03-15 17:06:52 -05001003 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001004 struct hci_cp_write_eir cp;
1005
Johan Hedberg504c8dc2012-02-23 13:30:41 +02001006 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001007 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +02001008
Johan Hedberg976eb202012-10-24 21:12:01 +03001009 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001010 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001011
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001012 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg890ea892013-03-15 17:06:52 -05001013 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001014
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001015 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -05001016 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001017
1018 memset(&cp, 0, sizeof(cp));
1019
1020 create_eir(hdev, cp.data);
1021
1022 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -05001023 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001024
1025 memcpy(hdev->eir, cp.data, sizeof(cp.data));
1026
Johan Hedberg890ea892013-03-15 17:06:52 -05001027 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001028}
1029
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001030static u8 get_service_classes(struct hci_dev *hdev)
1031{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -03001032 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001033 u8 val = 0;
1034
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -03001035 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001036 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001037
1038 return val;
1039}
1040
Johan Hedberg890ea892013-03-15 17:06:52 -05001041static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001042{
Johan Hedberg890ea892013-03-15 17:06:52 -05001043 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001044 u8 cod[3];
1045
1046 BT_DBG("%s", hdev->name);
1047
Johan Hedberg504c8dc2012-02-23 13:30:41 +02001048 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001049 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +02001050
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001051 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedbergf87ea1d2013-10-19 23:38:17 +03001052 return;
1053
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001054 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -05001055 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001056
1057 cod[0] = hdev->minor_class;
1058 cod[1] = hdev->major_class;
1059 cod[2] = get_service_classes(hdev);
1060
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001061 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Marcel Holtmann6acd7db2013-10-15 06:33:53 -07001062 cod[1] |= 0x20;
1063
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001064 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -05001065 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001066
Johan Hedberg890ea892013-03-15 17:06:52 -05001067 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001068}
1069
Johan Hedberga4858cb2014-02-25 19:56:31 +02001070static bool get_connectable(struct hci_dev *hdev)
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001071{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001072 struct mgmt_pending_cmd *cmd;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001073
1074 /* If there's a pending mgmt command the flag will not yet have
1075 * it's final value, so check for this first.
1076 */
1077 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1078 if (cmd) {
1079 struct mgmt_mode *cp = cmd->param;
Johan Hedberga4858cb2014-02-25 19:56:31 +02001080 return cp->val;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001081 }
1082
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001083 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001084}
1085
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001086static void disable_advertising(struct hci_request *req)
1087{
1088 u8 enable = 0x00;
1089
1090 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1091}
1092
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001093static void enable_advertising(struct hci_request *req)
1094{
1095 struct hci_dev *hdev = req->hdev;
1096 struct hci_cp_le_set_adv_param cp;
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001097 u8 own_addr_type, enable = 0x01;
Johan Hedberga4858cb2014-02-25 19:56:31 +02001098 bool connectable;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001099
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001100 if (hci_conn_num(hdev, LE_LINK) > 0)
1101 return;
1102
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001103 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001104 disable_advertising(req);
1105
Johan Hedberg5ce194c2014-07-08 15:07:49 +03001106 /* Clear the HCI_LE_ADV bit temporarily so that the
Johan Hedberg8d972502014-02-28 12:54:14 +02001107 * hci_update_random_address knows that it's safe to go ahead
1108 * and write a new random address. The flag will be set back on
1109 * as soon as the SET_ADV_ENABLE HCI command completes.
1110 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001111 hci_dev_clear_flag(hdev, HCI_LE_ADV);
Johan Hedberg8d972502014-02-28 12:54:14 +02001112
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001113 if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07001114 connectable = true;
1115 else
1116 connectable = get_connectable(hdev);
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001117
Johan Hedberga4858cb2014-02-25 19:56:31 +02001118 /* Set require_privacy to true only when non-connectable
1119 * advertising is used. In that case it is fine to use a
1120 * non-resolvable private address.
1121 */
1122 if (hci_update_random_address(req, !connectable, &own_addr_type) < 0)
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001123 return;
1124
Marcel Holtmann41c90c12014-02-23 20:25:55 -08001125 memset(&cp, 0, sizeof(cp));
Georg Lukas628531c2014-07-26 13:59:57 +02001126 cp.min_interval = cpu_to_le16(hdev->le_adv_min_interval);
1127 cp.max_interval = cpu_to_le16(hdev->le_adv_max_interval);
Johan Hedberga4858cb2014-02-25 19:56:31 +02001128 cp.type = connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001129 cp.own_address_type = own_addr_type;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001130 cp.channel_map = hdev->le_adv_channel_map;
1131
1132 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1133
1134 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1135}
1136
Johan Hedberg7d785252011-12-15 00:47:39 +02001137static void service_cache_off(struct work_struct *work)
1138{
1139 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001140 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -05001141 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +02001142
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001143 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +02001144 return;
1145
Johan Hedberg890ea892013-03-15 17:06:52 -05001146 hci_req_init(&req, hdev);
1147
Johan Hedberg7d785252011-12-15 00:47:39 +02001148 hci_dev_lock(hdev);
1149
Johan Hedberg890ea892013-03-15 17:06:52 -05001150 update_eir(&req);
1151 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001152
1153 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001154
1155 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +02001156}
1157
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001158static void rpa_expired(struct work_struct *work)
1159{
1160 struct hci_dev *hdev = container_of(work, struct hci_dev,
1161 rpa_expired.work);
1162 struct hci_request req;
1163
1164 BT_DBG("");
1165
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001166 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001167
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001168 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001169 return;
1170
1171 /* The generation of a new RPA and programming it into the
1172 * controller happens in the enable_advertising() function.
1173 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001174 hci_req_init(&req, hdev);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001175 enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001176 hci_req_run(&req, NULL);
1177}
1178
Johan Hedberg6a919082012-02-28 06:17:26 +02001179static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +02001180{
Johan Hedberg4f87da82012-03-02 19:55:56 +02001181 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +02001182 return;
1183
Johan Hedberg4f87da82012-03-02 19:55:56 +02001184 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001185 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +02001186
Johan Hedberg4f87da82012-03-02 19:55:56 +02001187 /* Non-mgmt controlled devices get this bit set
1188 * implicitly so that pairing works for them, however
1189 * for mgmt we require user-space to explicitly enable
1190 * it
1191 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001192 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +02001193}
1194
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001195static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001196 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001197{
1198 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001199
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001200 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001201
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001202 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001203
Johan Hedberg03811012010-12-08 00:21:06 +02001204 memset(&rp, 0, sizeof(rp));
1205
Johan Hedberg03811012010-12-08 00:21:06 +02001206 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001207
1208 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001209 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001210
1211 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1212 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1213
1214 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +02001215
1216 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001217 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +02001218
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001219 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001220
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001221 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1222 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +02001223}
1224
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001225static void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
Johan Hedberg03811012010-12-08 00:21:06 +02001226{
1227 sock_put(cmd->sk);
1228 kfree(cmd->param);
1229 kfree(cmd);
1230}
1231
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001232static struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
1233 struct hci_dev *hdev,
1234 void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001235{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001236 struct mgmt_pending_cmd *cmd;
Johan Hedberg03811012010-12-08 00:21:06 +02001237
Johan Hedbergfca20012014-06-28 17:54:05 +03001238 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001239 if (!cmd)
1240 return NULL;
1241
1242 cmd->opcode = opcode;
1243 cmd->index = hdev->id;
1244
Johan Hedberg323b0b82014-12-05 13:36:01 +02001245 cmd->param = kmemdup(data, len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001246 if (!cmd->param) {
1247 kfree(cmd);
1248 return NULL;
1249 }
1250
Johan Hedberg323b0b82014-12-05 13:36:01 +02001251 cmd->param_len = len;
Johan Hedberg03811012010-12-08 00:21:06 +02001252
1253 cmd->sk = sk;
1254 sock_hold(sk);
1255
1256 list_add(&cmd->list, &hdev->mgmt_pending);
1257
1258 return cmd;
1259}
1260
1261static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001262 void (*cb)(struct mgmt_pending_cmd *cmd,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001263 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001264 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02001265{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001266 struct mgmt_pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +02001267
Andre Guedesa3d09352013-02-01 11:21:30 -03001268 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +02001269 if (opcode > 0 && cmd->opcode != opcode)
1270 continue;
1271
1272 cb(cmd, data);
1273 }
1274}
1275
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001276static void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
Johan Hedberg03811012010-12-08 00:21:06 +02001277{
1278 list_del(&cmd->list);
1279 mgmt_pending_free(cmd);
1280}
1281
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001282static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001283{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001284 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001285
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001286 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1287 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001288}
1289
Marcel Holtmann1904a852015-01-11 13:50:44 -08001290static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001291{
1292 BT_DBG("%s status 0x%02x", hdev->name, status);
1293
Johan Hedberga3172b72014-02-28 09:33:44 +02001294 if (hci_conn_count(hdev) == 0) {
1295 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001296 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001297 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001298}
1299
Johan Hedberg23a48092014-07-08 16:05:06 +03001300static bool hci_stop_discovery(struct hci_request *req)
Johan Hedberg21a60d32014-06-10 14:05:58 +03001301{
1302 struct hci_dev *hdev = req->hdev;
1303 struct hci_cp_remote_name_req_cancel cp;
1304 struct inquiry_entry *e;
1305
1306 switch (hdev->discovery.state) {
1307 case DISCOVERY_FINDING:
1308 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
1309 hci_req_add(req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
1310 } else {
1311 cancel_delayed_work(&hdev->le_scan_disable);
1312 hci_req_add_le_scan_disable(req);
1313 }
1314
Johan Hedberg23a48092014-07-08 16:05:06 +03001315 return true;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001316
1317 case DISCOVERY_RESOLVING:
1318 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
1319 NAME_PENDING);
1320 if (!e)
Johan Hedberg23a48092014-07-08 16:05:06 +03001321 break;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001322
1323 bacpy(&cp.bdaddr, &e->data.bdaddr);
1324 hci_req_add(req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
1325 &cp);
1326
Johan Hedberg23a48092014-07-08 16:05:06 +03001327 return true;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001328
1329 default:
1330 /* Passive scanning */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001331 if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
Johan Hedberg21a60d32014-06-10 14:05:58 +03001332 hci_req_add_le_scan_disable(req);
Johan Hedberg23a48092014-07-08 16:05:06 +03001333 return true;
1334 }
1335
Johan Hedberg21a60d32014-06-10 14:05:58 +03001336 break;
1337 }
Johan Hedberg23a48092014-07-08 16:05:06 +03001338
1339 return false;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001340}
1341
Johan Hedberg8b064a32014-02-24 14:52:22 +02001342static int clean_up_hci_state(struct hci_dev *hdev)
1343{
1344 struct hci_request req;
1345 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001346 bool discov_stopped;
1347 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001348
1349 hci_req_init(&req, hdev);
1350
1351 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1352 test_bit(HCI_PSCAN, &hdev->flags)) {
1353 u8 scan = 0x00;
1354 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1355 }
1356
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001357 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedberg8b064a32014-02-24 14:52:22 +02001358 disable_advertising(&req);
1359
Johan Hedberg23a48092014-07-08 16:05:06 +03001360 discov_stopped = hci_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001361
1362 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
1363 struct hci_cp_disconnect dc;
Johan Hedbergc9910d02014-02-27 14:35:12 +02001364 struct hci_cp_reject_conn_req rej;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001365
Johan Hedbergc9910d02014-02-27 14:35:12 +02001366 switch (conn->state) {
1367 case BT_CONNECTED:
1368 case BT_CONFIG:
1369 dc.handle = cpu_to_le16(conn->handle);
1370 dc.reason = 0x15; /* Terminated due to Power Off */
1371 hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1372 break;
1373 case BT_CONNECT:
1374 if (conn->type == LE_LINK)
1375 hci_req_add(&req, HCI_OP_LE_CREATE_CONN_CANCEL,
1376 0, NULL);
1377 else if (conn->type == ACL_LINK)
1378 hci_req_add(&req, HCI_OP_CREATE_CONN_CANCEL,
1379 6, &conn->dst);
1380 break;
1381 case BT_CONNECT2:
1382 bacpy(&rej.bdaddr, &conn->dst);
1383 rej.reason = 0x15; /* Terminated due to Power Off */
1384 if (conn->type == ACL_LINK)
1385 hci_req_add(&req, HCI_OP_REJECT_CONN_REQ,
1386 sizeof(rej), &rej);
1387 else if (conn->type == SCO_LINK)
1388 hci_req_add(&req, HCI_OP_REJECT_SYNC_CONN_REQ,
1389 sizeof(rej), &rej);
1390 break;
1391 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001392 }
1393
Johan Hedberg23a48092014-07-08 16:05:06 +03001394 err = hci_req_run(&req, clean_up_hci_complete);
1395 if (!err && discov_stopped)
1396 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1397
1398 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001399}
1400
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001401static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001402 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001403{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001404 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001405 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001406 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001407
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001408 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001409
Johan Hedberga7e80f22013-01-09 16:05:19 +02001410 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001411 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1412 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001413
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001414 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001415
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001416 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001417 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1418 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001419 goto failed;
1420 }
1421
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001422 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
1423 cancel_delayed_work(&hdev->power_off);
1424
1425 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +02001426 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
1427 data, len);
1428 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001429 goto failed;
1430 }
1431 }
1432
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001433 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001434 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001435 goto failed;
1436 }
1437
Johan Hedberg03811012010-12-08 00:21:06 +02001438 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1439 if (!cmd) {
1440 err = -ENOMEM;
1441 goto failed;
1442 }
1443
Johan Hedberg8b064a32014-02-24 14:52:22 +02001444 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001445 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001446 err = 0;
1447 } else {
1448 /* Disconnect connections, stop scans, etc */
1449 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001450 if (!err)
1451 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1452 HCI_POWER_OFF_TIMEOUT);
Johan Hedberg03811012010-12-08 00:21:06 +02001453
Johan Hedberg8b064a32014-02-24 14:52:22 +02001454 /* ENODATA means there were no HCI commands queued */
1455 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001456 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001457 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1458 err = 0;
1459 }
1460 }
Johan Hedberg03811012010-12-08 00:21:06 +02001461
1462failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001463 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001464 return err;
1465}
1466
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001467static int new_settings(struct hci_dev *hdev, struct sock *skip)
1468{
1469 __le32 ev;
1470
1471 ev = cpu_to_le32(get_current_settings(hdev));
1472
1473 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1474}
1475
Johan Hedberg91a668b2014-07-09 13:28:26 +03001476int mgmt_new_settings(struct hci_dev *hdev)
1477{
1478 return new_settings(hdev, NULL);
1479}
1480
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001481struct cmd_lookup {
1482 struct sock *sk;
1483 struct hci_dev *hdev;
1484 u8 mgmt_status;
1485};
1486
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001487static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001488{
1489 struct cmd_lookup *match = data;
1490
1491 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1492
1493 list_del(&cmd->list);
1494
1495 if (match->sk == NULL) {
1496 match->sk = cmd->sk;
1497 sock_hold(match->sk);
1498 }
1499
1500 mgmt_pending_free(cmd);
1501}
1502
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001503static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001504{
1505 u8 *status = data;
1506
Johan Hedberga69e8372015-03-06 21:08:53 +02001507 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001508 mgmt_pending_remove(cmd);
1509}
1510
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001511static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001512{
1513 if (cmd->cmd_complete) {
1514 u8 *status = data;
1515
1516 cmd->cmd_complete(cmd, *status);
1517 mgmt_pending_remove(cmd);
1518
1519 return;
1520 }
1521
1522 cmd_status_rsp(cmd, data);
1523}
1524
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001525static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001526{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001527 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1528 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001529}
1530
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001531static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001532{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001533 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1534 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001535}
1536
Johan Hedberge6fe7982013-10-02 15:45:22 +03001537static u8 mgmt_bredr_support(struct hci_dev *hdev)
1538{
1539 if (!lmp_bredr_capable(hdev))
1540 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001541 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001542 return MGMT_STATUS_REJECTED;
1543 else
1544 return MGMT_STATUS_SUCCESS;
1545}
1546
1547static u8 mgmt_le_support(struct hci_dev *hdev)
1548{
1549 if (!lmp_le_capable(hdev))
1550 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001551 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001552 return MGMT_STATUS_REJECTED;
1553 else
1554 return MGMT_STATUS_SUCCESS;
1555}
1556
Marcel Holtmann1904a852015-01-11 13:50:44 -08001557static void set_discoverable_complete(struct hci_dev *hdev, u8 status,
1558 u16 opcode)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001559{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001560 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001561 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001562 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001563 bool changed;
1564
1565 BT_DBG("status 0x%02x", status);
1566
1567 hci_dev_lock(hdev);
1568
1569 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1570 if (!cmd)
1571 goto unlock;
1572
1573 if (status) {
1574 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001575 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001576 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001577 goto remove_cmd;
1578 }
1579
1580 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001581 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001582 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1583 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001584
1585 if (hdev->discov_timeout > 0) {
1586 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1587 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1588 to);
1589 }
1590 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001591 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1592 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001593 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001594
1595 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1596
1597 if (changed)
1598 new_settings(hdev, cmd->sk);
1599
Marcel Holtmann970ba522013-10-15 06:33:57 -07001600 /* When the discoverable mode gets changed, make sure
1601 * that class of device has the limited discoverable
Johan Hedberg432df052014-08-01 11:13:31 +03001602 * bit correctly set. Also update page scan based on whitelist
1603 * entries.
Marcel Holtmann970ba522013-10-15 06:33:57 -07001604 */
1605 hci_req_init(&req, hdev);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001606 __hci_update_page_scan(&req);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001607 update_class(&req);
1608 hci_req_run(&req, NULL);
1609
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001610remove_cmd:
1611 mgmt_pending_remove(cmd);
1612
1613unlock:
1614 hci_dev_unlock(hdev);
1615}
1616
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001617static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001618 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001619{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001620 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001621 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001622 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001623 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001624 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001625 int err;
Johan Hedberge41d8b42010-12-13 21:07:03 +02001626
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001627 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001628
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001629 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1630 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001631 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1632 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001633
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001634 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001635 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1636 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001637
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001638 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001639
1640 /* Disabling discoverable requires that no timeout is set,
1641 * and enabling limited discoverable requires a timeout.
1642 */
1643 if ((cp->val == 0x00 && timeout > 0) ||
1644 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001645 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1646 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001647
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001648 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001649
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001650 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001651 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1652 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001653 goto failed;
1654 }
1655
1656 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001657 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001658 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1659 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001660 goto failed;
1661 }
1662
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001663 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001664 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1665 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001666 goto failed;
1667 }
1668
1669 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001670 bool changed = false;
1671
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001672 /* Setting limited discoverable when powered off is
1673 * not a valid operation since it requires a timeout
1674 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1675 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001676 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001677 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1678 changed = true;
1679 }
1680
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001681 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001682 if (err < 0)
1683 goto failed;
1684
1685 if (changed)
1686 err = new_settings(hdev, sk);
1687
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001688 goto failed;
1689 }
1690
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001691 /* If the current mode is the same, then just update the timeout
1692 * value with the new value. And if only the timeout gets updated,
1693 * then no need for any HCI transactions.
1694 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001695 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1696 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1697 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001698 cancel_delayed_work(&hdev->discov_off);
1699 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001700
Marcel Holtmann36261542013-10-15 08:28:51 -07001701 if (cp->val && hdev->discov_timeout > 0) {
1702 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001703 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001704 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001705 }
1706
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001707 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001708 goto failed;
1709 }
1710
1711 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1712 if (!cmd) {
1713 err = -ENOMEM;
1714 goto failed;
1715 }
1716
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001717 /* Cancel any potential discoverable timeout that might be
1718 * still active and store new timeout value. The arming of
1719 * the timeout happens in the complete handler.
1720 */
1721 cancel_delayed_work(&hdev->discov_off);
1722 hdev->discov_timeout = timeout;
1723
Johan Hedbergb456f872013-10-19 23:38:22 +03001724 /* Limited discoverable mode */
1725 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001726 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001727 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001728 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001729
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001730 hci_req_init(&req, hdev);
1731
Johan Hedberg9a43e252013-10-20 19:00:07 +03001732 /* The procedure for LE-only controllers is much simpler - just
1733 * update the advertising data.
1734 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001735 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg9a43e252013-10-20 19:00:07 +03001736 goto update_ad;
1737
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001738 scan = SCAN_PAGE;
1739
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001740 if (cp->val) {
1741 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001742
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001743 if (cp->val == 0x02) {
1744 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001745 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001746 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1747 hci_cp.iac_lap[1] = 0x8b;
1748 hci_cp.iac_lap[2] = 0x9e;
1749 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1750 hci_cp.iac_lap[4] = 0x8b;
1751 hci_cp.iac_lap[5] = 0x9e;
1752 } else {
1753 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001754 hci_cp.num_iac = 1;
1755 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1756 hci_cp.iac_lap[1] = 0x8b;
1757 hci_cp.iac_lap[2] = 0x9e;
1758 }
1759
1760 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1761 (hci_cp.num_iac * 3) + 1, &hci_cp);
1762
1763 scan |= SCAN_INQUIRY;
1764 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001765 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001766 }
1767
1768 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001769
Johan Hedberg9a43e252013-10-20 19:00:07 +03001770update_ad:
1771 update_adv_data(&req);
1772
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001773 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001774 if (err < 0)
1775 mgmt_pending_remove(cmd);
1776
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001777failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001778 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001779 return err;
1780}
1781
Johan Hedberg406d7802013-03-15 17:07:09 -05001782static void write_fast_connectable(struct hci_request *req, bool enable)
1783{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001784 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001785 struct hci_cp_write_page_scan_activity acp;
1786 u8 type;
1787
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001788 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg547003b2013-10-21 16:51:53 +03001789 return;
1790
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001791 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1792 return;
1793
Johan Hedberg406d7802013-03-15 17:07:09 -05001794 if (enable) {
1795 type = PAGE_SCAN_TYPE_INTERLACED;
1796
1797 /* 160 msec page scan interval */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001798 acp.interval = cpu_to_le16(0x0100);
Johan Hedberg406d7802013-03-15 17:07:09 -05001799 } else {
1800 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1801
1802 /* default 1.28 sec page scan */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001803 acp.interval = cpu_to_le16(0x0800);
Johan Hedberg406d7802013-03-15 17:07:09 -05001804 }
1805
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001806 acp.window = cpu_to_le16(0x0012);
Johan Hedberg406d7802013-03-15 17:07:09 -05001807
Johan Hedbergbd98b992013-03-15 17:07:13 -05001808 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1809 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1810 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1811 sizeof(acp), &acp);
1812
1813 if (hdev->page_scan_type != type)
1814 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001815}
1816
Marcel Holtmann1904a852015-01-11 13:50:44 -08001817static void set_connectable_complete(struct hci_dev *hdev, u8 status,
1818 u16 opcode)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001819{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001820 struct mgmt_pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001821 struct mgmt_mode *cp;
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001822 bool conn_changed, discov_changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001823
1824 BT_DBG("status 0x%02x", status);
1825
1826 hci_dev_lock(hdev);
1827
1828 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1829 if (!cmd)
1830 goto unlock;
1831
Johan Hedberg37438c12013-10-14 16:20:05 +03001832 if (status) {
1833 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001834 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001835 goto remove_cmd;
1836 }
1837
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001838 cp = cmd->param;
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001839 if (cp->val) {
1840 conn_changed = !test_and_set_bit(HCI_CONNECTABLE,
1841 &hdev->dev_flags);
1842 discov_changed = false;
1843 } else {
1844 conn_changed = test_and_clear_bit(HCI_CONNECTABLE,
1845 &hdev->dev_flags);
1846 discov_changed = test_and_clear_bit(HCI_DISCOVERABLE,
1847 &hdev->dev_flags);
1848 }
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001849
Johan Hedberg2b76f452013-03-15 17:07:04 -05001850 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1851
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001852 if (conn_changed || discov_changed) {
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001853 new_settings(hdev, cmd->sk);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001854 hci_update_page_scan(hdev);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001855 if (discov_changed)
1856 mgmt_update_adv_data(hdev);
Johan Hedberg2b7be332014-07-07 14:40:22 +03001857 hci_update_background_scan(hdev);
1858 }
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001859
Johan Hedberg37438c12013-10-14 16:20:05 +03001860remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001861 mgmt_pending_remove(cmd);
1862
1863unlock:
1864 hci_dev_unlock(hdev);
1865}
1866
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001867static int set_connectable_update_settings(struct hci_dev *hdev,
1868 struct sock *sk, u8 val)
1869{
1870 bool changed = false;
1871 int err;
1872
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001873 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001874 changed = true;
1875
1876 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001877 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001878 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001879 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1880 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001881 }
1882
1883 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1884 if (err < 0)
1885 return err;
1886
Johan Hedberg562064e2014-07-08 16:35:34 +03001887 if (changed) {
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001888 hci_update_page_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001889 hci_update_background_scan(hdev);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001890 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001891 }
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001892
1893 return 0;
1894}
1895
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001896static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001897 u16 len)
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001898{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001899 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001900 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001901 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001902 u8 scan;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001903 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001904
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001905 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001906
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001907 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1908 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001909 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1910 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001911
Johan Hedberga7e80f22013-01-09 16:05:19 +02001912 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001913 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1914 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001915
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001916 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001917
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001918 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001919 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001920 goto failed;
1921 }
1922
1923 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001924 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001925 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1926 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001927 goto failed;
1928 }
1929
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001930 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1931 if (!cmd) {
1932 err = -ENOMEM;
1933 goto failed;
1934 }
1935
Johan Hedberg2b76f452013-03-15 17:07:04 -05001936 hci_req_init(&req, hdev);
1937
Johan Hedberg9a43e252013-10-20 19:00:07 +03001938 /* If BR/EDR is not enabled and we disable advertising as a
1939 * by-product of disabling connectable, we need to update the
1940 * advertising flags.
1941 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001942 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg9a43e252013-10-20 19:00:07 +03001943 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001944 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
1945 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg9a43e252013-10-20 19:00:07 +03001946 }
1947 update_adv_data(&req);
1948 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001949 if (cp->val) {
1950 scan = SCAN_PAGE;
1951 } else {
Johan Hedberg3bd27242014-07-28 20:53:58 +03001952 /* If we don't have any whitelist entries just
1953 * disable all scanning. If there are entries
1954 * and we had both page and inquiry scanning
1955 * enabled then fall back to only page scanning.
1956 * Otherwise no changes are needed.
1957 */
1958 if (list_empty(&hdev->whitelist))
1959 scan = SCAN_DISABLED;
1960 else if (test_bit(HCI_ISCAN, &hdev->flags))
1961 scan = SCAN_PAGE;
1962 else
1963 goto no_scan_update;
Johan Hedberg9b742462013-10-14 16:20:03 +03001964
1965 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001966 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001967 cancel_delayed_work(&hdev->discov_off);
1968 }
1969
1970 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1971 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001972
Johan Hedberg3bd27242014-07-28 20:53:58 +03001973no_scan_update:
Johan Hedberge8b12022014-07-10 10:51:27 +03001974 /* Update the advertising parameters if necessary */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001975 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001976 enable_advertising(&req);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001977
Johan Hedberg2b76f452013-03-15 17:07:04 -05001978 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001979 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001980 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001981 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03001982 err = set_connectable_update_settings(hdev, sk,
1983 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03001984 goto failed;
1985 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001986
1987failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001988 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001989 return err;
1990}
1991
Johan Hedbergb2939472014-07-30 09:22:23 +03001992static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001993 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001994{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001995 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001996 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001997 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001998
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001999 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002000
Johan Hedberga7e80f22013-01-09 16:05:19 +02002001 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002002 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
2003 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002004
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002005 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002006
2007 if (cp->val)
Johan Hedbergb6ae8452014-07-30 09:22:22 +03002008 changed = !test_and_set_bit(HCI_BONDABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002009 else
Johan Hedbergb6ae8452014-07-30 09:22:22 +03002010 changed = test_and_clear_bit(HCI_BONDABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002011
Johan Hedbergb2939472014-07-30 09:22:23 +03002012 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002013 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07002014 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002015
Marcel Holtmann55594352013-10-06 16:11:57 -07002016 if (changed)
2017 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002018
Marcel Holtmann55594352013-10-06 16:11:57 -07002019unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002020 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002021 return err;
2022}
Johan Hedberg72a734e2010-12-30 00:38:22 +02002023
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002024static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
2025 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002026{
2027 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002028 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03002029 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002030 int err;
2031
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002032 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002033
Johan Hedberge6fe7982013-10-02 15:45:22 +03002034 status = mgmt_bredr_support(hdev);
2035 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002036 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2037 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03002038
Johan Hedberga7e80f22013-01-09 16:05:19 +02002039 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002040 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2041 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002042
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002043 hci_dev_lock(hdev);
2044
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002045 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02002046 bool changed = false;
2047
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002048 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02002049 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
2050 changed = true;
2051 }
2052
2053 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
2054 if (err < 0)
2055 goto failed;
2056
2057 if (changed)
2058 err = new_settings(hdev, sk);
2059
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002060 goto failed;
2061 }
2062
2063 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002064 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2065 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002066 goto failed;
2067 }
2068
2069 val = !!cp->val;
2070
2071 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
2072 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
2073 goto failed;
2074 }
2075
2076 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
2077 if (!cmd) {
2078 err = -ENOMEM;
2079 goto failed;
2080 }
2081
2082 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
2083 if (err < 0) {
2084 mgmt_pending_remove(cmd);
2085 goto failed;
2086 }
2087
2088failed:
2089 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002090 return err;
2091}
2092
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002093static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002094{
2095 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002096 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07002097 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002098 int err;
2099
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002100 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002101
Marcel Holtmanncdba5282013-10-02 21:31:52 -07002102 status = mgmt_bredr_support(hdev);
2103 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002104 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07002105
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002106 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002107 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2108 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002109
Johan Hedberga7e80f22013-01-09 16:05:19 +02002110 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002111 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2112 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002113
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002114 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02002115
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002116 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002117 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02002118
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002119 if (cp->val) {
2120 changed = !test_and_set_bit(HCI_SSP_ENABLED,
2121 &hdev->dev_flags);
2122 } else {
2123 changed = test_and_clear_bit(HCI_SSP_ENABLED,
2124 &hdev->dev_flags);
2125 if (!changed)
2126 changed = test_and_clear_bit(HCI_HS_ENABLED,
2127 &hdev->dev_flags);
2128 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002129 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02002130 }
2131
2132 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
2133 if (err < 0)
2134 goto failed;
2135
2136 if (changed)
2137 err = new_settings(hdev, sk);
2138
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002139 goto failed;
2140 }
2141
Johan Hedberg94d52da2015-02-19 17:38:06 +02002142 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002143 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2144 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002145 goto failed;
2146 }
2147
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002148 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002149 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
2150 goto failed;
2151 }
2152
2153 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
2154 if (!cmd) {
2155 err = -ENOMEM;
2156 goto failed;
2157 }
2158
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002159 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03002160 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
2161 sizeof(cp->val), &cp->val);
2162
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07002163 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002164 if (err < 0) {
2165 mgmt_pending_remove(cmd);
2166 goto failed;
2167 }
2168
2169failed:
2170 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002171 return err;
2172}
2173
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002174static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002175{
2176 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07002177 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03002178 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07002179 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002180
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002181 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002182
Johan Hedberge6fe7982013-10-02 15:45:22 +03002183 status = mgmt_bredr_support(hdev);
2184 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002185 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002186
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002187 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002188 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2189 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002190
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002191 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02002192 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2193 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002194
Johan Hedberga7e80f22013-01-09 16:05:19 +02002195 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002196 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2197 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002198
Marcel Holtmannee392692013-10-01 22:59:23 -07002199 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002200
Johan Hedberga2cb01d2015-02-19 17:38:07 +02002201 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002202 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2203 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02002204 goto unlock;
2205 }
2206
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002207 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07002208 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002209 } else {
2210 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002211 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2212 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002213 goto unlock;
2214 }
2215
Marcel Holtmannee392692013-10-01 22:59:23 -07002216 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002217 }
Marcel Holtmannee392692013-10-01 22:59:23 -07002218
2219 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
2220 if (err < 0)
2221 goto unlock;
2222
2223 if (changed)
2224 err = new_settings(hdev, sk);
2225
2226unlock:
2227 hci_dev_unlock(hdev);
2228 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002229}
2230
Marcel Holtmann1904a852015-01-11 13:50:44 -08002231static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002232{
2233 struct cmd_lookup match = { NULL, hdev };
2234
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302235 hci_dev_lock(hdev);
2236
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002237 if (status) {
2238 u8 mgmt_err = mgmt_status(status);
2239
2240 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
2241 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302242 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002243 }
2244
2245 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
2246
2247 new_settings(hdev, match.sk);
2248
2249 if (match.sk)
2250 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002251
2252 /* Make sure the controller has a good default for
2253 * advertising data. Restrict the update to when LE
2254 * has actually been enabled. During power on, the
2255 * update in powered_update_hci will take care of it.
2256 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002257 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002258 struct hci_request req;
2259
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002260 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07002261 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07002262 update_scan_rsp_data(&req);
Johan Hedberg2cf22212014-12-19 22:26:00 +02002263 __hci_update_background_scan(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002264 hci_req_run(&req, NULL);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002265 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302266
2267unlock:
2268 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002269}
2270
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002271static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002272{
2273 struct mgmt_mode *cp = data;
2274 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002275 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002276 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002277 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002278 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002279
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002280 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002281
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002282 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002283 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2284 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002285
Johan Hedberga7e80f22013-01-09 16:05:19 +02002286 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002287 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2288 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002289
Johan Hedbergc73eee92013-04-19 18:35:21 +03002290 /* LE-only devices do not allow toggling LE on/off */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002291 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02002292 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2293 MGMT_STATUS_REJECTED);
Johan Hedbergc73eee92013-04-19 18:35:21 +03002294
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002295 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002296
2297 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02002298 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002299
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002300 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02002301 bool changed = false;
2302
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002303 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02002304 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
2305 changed = true;
2306 }
2307
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002308 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002309 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03002310 changed = true;
2311 }
2312
Johan Hedberg06199cf2012-02-22 16:37:11 +02002313 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
2314 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08002315 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002316
2317 if (changed)
2318 err = new_settings(hdev, sk);
2319
Johan Hedberg1de028c2012-02-29 19:55:35 -08002320 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002321 }
2322
Johan Hedberg4375f102013-09-25 13:26:10 +03002323 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
2324 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002325 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2326 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002327 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002328 }
2329
2330 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
2331 if (!cmd) {
2332 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08002333 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002334 }
2335
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002336 hci_req_init(&req, hdev);
2337
Johan Hedberg06199cf2012-02-22 16:37:11 +02002338 memset(&hci_cp, 0, sizeof(hci_cp));
2339
2340 if (val) {
2341 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02002342 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002343 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002344 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002345 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002346 }
2347
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002348 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
2349 &hci_cp);
2350
2351 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05302352 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002353 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002354
Johan Hedberg1de028c2012-02-29 19:55:35 -08002355unlock:
2356 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002357 return err;
2358}
2359
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002360/* This is a helper function to test for pending mgmt commands that can
2361 * cause CoD or EIR HCI commands. We can only allow one such pending
2362 * mgmt command at a time since otherwise we cannot easily track what
2363 * the current values are, will be, and based on that calculate if a new
2364 * HCI command needs to be sent and if yes with what value.
2365 */
2366static bool pending_eir_or_class(struct hci_dev *hdev)
2367{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002368 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002369
2370 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2371 switch (cmd->opcode) {
2372 case MGMT_OP_ADD_UUID:
2373 case MGMT_OP_REMOVE_UUID:
2374 case MGMT_OP_SET_DEV_CLASS:
2375 case MGMT_OP_SET_POWERED:
2376 return true;
2377 }
2378 }
2379
2380 return false;
2381}
2382
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002383static const u8 bluetooth_base_uuid[] = {
2384 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2385 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2386};
2387
2388static u8 get_uuid_size(const u8 *uuid)
2389{
2390 u32 val;
2391
2392 if (memcmp(uuid, bluetooth_base_uuid, 12))
2393 return 128;
2394
2395 val = get_unaligned_le32(&uuid[12]);
2396 if (val > 0xffff)
2397 return 32;
2398
2399 return 16;
2400}
2401
Johan Hedberg92da6092013-03-15 17:06:55 -05002402static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2403{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002404 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002405
2406 hci_dev_lock(hdev);
2407
2408 cmd = mgmt_pending_find(mgmt_op, hdev);
2409 if (!cmd)
2410 goto unlock;
2411
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002412 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2413 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002414
2415 mgmt_pending_remove(cmd);
2416
2417unlock:
2418 hci_dev_unlock(hdev);
2419}
2420
Marcel Holtmann1904a852015-01-11 13:50:44 -08002421static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002422{
2423 BT_DBG("status 0x%02x", status);
2424
2425 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2426}
2427
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002428static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002429{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002430 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002431 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002432 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002433 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002434 int err;
2435
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002436 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002437
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002438 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002439
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002440 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002441 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2442 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002443 goto failed;
2444 }
2445
Andre Guedes92c4c202012-06-07 19:05:44 -03002446 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002447 if (!uuid) {
2448 err = -ENOMEM;
2449 goto failed;
2450 }
2451
2452 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002453 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002454 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002455
Johan Hedbergde66aa62013-01-27 00:31:27 +02002456 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002457
Johan Hedberg890ea892013-03-15 17:06:52 -05002458 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002459
Johan Hedberg890ea892013-03-15 17:06:52 -05002460 update_class(&req);
2461 update_eir(&req);
2462
Johan Hedberg92da6092013-03-15 17:06:55 -05002463 err = hci_req_run(&req, add_uuid_complete);
2464 if (err < 0) {
2465 if (err != -ENODATA)
2466 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002467
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002468 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2469 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002470 goto failed;
2471 }
2472
2473 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002474 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002475 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002476 goto failed;
2477 }
2478
2479 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002480
2481failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002482 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002483 return err;
2484}
2485
Johan Hedberg24b78d02012-02-23 23:24:30 +02002486static bool enable_service_cache(struct hci_dev *hdev)
2487{
2488 if (!hdev_is_powered(hdev))
2489 return false;
2490
2491 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002492 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2493 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002494 return true;
2495 }
2496
2497 return false;
2498}
2499
Marcel Holtmann1904a852015-01-11 13:50:44 -08002500static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002501{
2502 BT_DBG("status 0x%02x", status);
2503
2504 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2505}
2506
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002507static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002508 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002509{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002510 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002511 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002512 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002513 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 -05002514 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002515 int err, found;
2516
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002517 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002518
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002519 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002520
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002521 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002522 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2523 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002524 goto unlock;
2525 }
2526
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002527 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002528 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002529
Johan Hedberg24b78d02012-02-23 23:24:30 +02002530 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002531 err = mgmt_cmd_complete(sk, hdev->id,
2532 MGMT_OP_REMOVE_UUID,
2533 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002534 goto unlock;
2535 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002536
Johan Hedberg9246a862012-02-23 21:33:16 +02002537 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002538 }
2539
2540 found = 0;
2541
Johan Hedberg056341c2013-01-27 00:31:30 +02002542 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002543 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2544 continue;
2545
2546 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002547 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002548 found++;
2549 }
2550
2551 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002552 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2553 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002554 goto unlock;
2555 }
2556
Johan Hedberg9246a862012-02-23 21:33:16 +02002557update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002558 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002559
Johan Hedberg890ea892013-03-15 17:06:52 -05002560 update_class(&req);
2561 update_eir(&req);
2562
Johan Hedberg92da6092013-03-15 17:06:55 -05002563 err = hci_req_run(&req, remove_uuid_complete);
2564 if (err < 0) {
2565 if (err != -ENODATA)
2566 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002567
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002568 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 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_REMOVE_UUID, 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 Hedberg2aeb9a12011-01-04 12:08:51 +02002580
2581unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002582 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002583 return err;
2584}
2585
Marcel Holtmann1904a852015-01-11 13:50:44 -08002586static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002587{
2588 BT_DBG("status 0x%02x", status);
2589
2590 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2591}
2592
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002593static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002594 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002595{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002596 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002597 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002598 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002599 int err;
2600
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002601 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002602
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002603 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002604 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2605 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002606
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002607 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002608
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002609 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002610 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2611 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002612 goto unlock;
2613 }
2614
2615 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002616 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2617 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002618 goto unlock;
2619 }
2620
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002621 hdev->major_class = cp->major;
2622 hdev->minor_class = cp->minor;
2623
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002624 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002625 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2626 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002627 goto unlock;
2628 }
2629
Johan Hedberg890ea892013-03-15 17:06:52 -05002630 hci_req_init(&req, hdev);
2631
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002632 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002633 hci_dev_unlock(hdev);
2634 cancel_delayed_work_sync(&hdev->service_cache);
2635 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002636 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002637 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002638
Johan Hedberg890ea892013-03-15 17:06:52 -05002639 update_class(&req);
2640
Johan Hedberg92da6092013-03-15 17:06:55 -05002641 err = hci_req_run(&req, set_class_complete);
2642 if (err < 0) {
2643 if (err != -ENODATA)
2644 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002645
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002646 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2647 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002648 goto unlock;
2649 }
2650
2651 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002652 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002653 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002654 goto unlock;
2655 }
2656
2657 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002658
Johan Hedbergb5235a62012-02-21 14:32:24 +02002659unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002660 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002661 return err;
2662}
2663
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002664static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002665 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002666{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002667 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002668 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2669 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002670 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002671 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002672 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002673
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002674 BT_DBG("request for %s", hdev->name);
2675
2676 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002677 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2678 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002679
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002680 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002681 if (key_count > max_key_count) {
2682 BT_ERR("load_link_keys: too big key_count value %u",
2683 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002684 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2685 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002686 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002687
Johan Hedberg86742e12011-11-07 23:13:38 +02002688 expected_len = sizeof(*cp) + key_count *
2689 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002690 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002691 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002692 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002693 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2694 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002695 }
2696
Johan Hedberg4ae14302013-01-20 14:27:13 +02002697 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002698 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2699 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002700
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002701 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002702 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002703
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002704 for (i = 0; i < key_count; i++) {
2705 struct mgmt_link_key_info *key = &cp->keys[i];
2706
Marcel Holtmann8e991132014-01-10 02:07:25 -08002707 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002708 return mgmt_cmd_status(sk, hdev->id,
2709 MGMT_OP_LOAD_LINK_KEYS,
2710 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002711 }
2712
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002713 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002714
2715 hci_link_keys_clear(hdev);
2716
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002717 if (cp->debug_keys)
Johan Hedberg0663b292014-06-24 13:15:50 +03002718 changed = !test_and_set_bit(HCI_KEEP_DEBUG_KEYS,
2719 &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002720 else
Johan Hedberg0663b292014-06-24 13:15:50 +03002721 changed = test_and_clear_bit(HCI_KEEP_DEBUG_KEYS,
2722 &hdev->dev_flags);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002723
2724 if (changed)
2725 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002726
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002727 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002728 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002729
Johan Hedberg58e92932014-06-24 14:00:26 +03002730 /* Always ignore debug keys and require a new pairing if
2731 * the user wants to use them.
2732 */
2733 if (key->type == HCI_LK_DEBUG_COMBINATION)
2734 continue;
2735
Johan Hedberg7652ff62014-06-24 13:15:49 +03002736 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2737 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002738 }
2739
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002740 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002741
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002742 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002743
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002744 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002745}
2746
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002747static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002748 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002749{
2750 struct mgmt_ev_device_unpaired ev;
2751
2752 bacpy(&ev.addr.bdaddr, bdaddr);
2753 ev.addr.type = addr_type;
2754
2755 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002756 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002757}
2758
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002759static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002760 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002761{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002762 struct mgmt_cp_unpair_device *cp = data;
2763 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002764 struct hci_cp_disconnect dc;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002765 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002766 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002767 int err;
2768
Johan Hedberga8a1d192011-11-10 15:54:38 +02002769 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002770 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2771 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002772
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002773 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002774 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2775 MGMT_STATUS_INVALID_PARAMS,
2776 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002777
Johan Hedberg118da702013-01-20 14:27:20 +02002778 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002779 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2780 MGMT_STATUS_INVALID_PARAMS,
2781 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002782
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002783 hci_dev_lock(hdev);
2784
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002785 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002786 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2787 MGMT_STATUS_NOT_POWERED, &rp,
2788 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002789 goto unlock;
2790 }
2791
Johan Hedberge0b2b272014-02-18 17:14:31 +02002792 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002793 /* If disconnection is requested, then look up the
2794 * connection. If the remote device is connected, it
2795 * will be later used to terminate the link.
2796 *
2797 * Setting it to NULL explicitly will cause no
2798 * termination of the link.
2799 */
2800 if (cp->disconnect)
2801 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2802 &cp->addr.bdaddr);
2803 else
2804 conn = NULL;
2805
Johan Hedberg124f6e32012-02-09 13:50:12 +02002806 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedberge0b2b272014-02-18 17:14:31 +02002807 } else {
2808 u8 addr_type;
2809
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002810 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
2811 &cp->addr.bdaddr);
2812 if (conn) {
2813 /* Defer clearing up the connection parameters
2814 * until closing to give a chance of keeping
2815 * them if a repairing happens.
2816 */
2817 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2818
2819 /* If disconnection is not requested, then
2820 * clear the connection variable so that the
2821 * link is not terminated.
2822 */
2823 if (!cp->disconnect)
2824 conn = NULL;
2825 }
2826
Johan Hedberge0b2b272014-02-18 17:14:31 +02002827 if (cp->addr.type == BDADDR_LE_PUBLIC)
2828 addr_type = ADDR_LE_DEV_PUBLIC;
2829 else
2830 addr_type = ADDR_LE_DEV_RANDOM;
2831
Johan Hedberga7ec7332014-02-18 17:14:35 +02002832 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2833
Johan Hedberge0b2b272014-02-18 17:14:31 +02002834 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
2835 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002836
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002837 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002838 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2839 MGMT_STATUS_NOT_PAIRED, &rp,
2840 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002841 goto unlock;
2842 }
2843
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002844 /* If the connection variable is set, then termination of the
2845 * link is requested.
2846 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002847 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002848 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2849 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002850 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002851 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002852 }
2853
Johan Hedberg124f6e32012-02-09 13:50:12 +02002854 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002855 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002856 if (!cmd) {
2857 err = -ENOMEM;
2858 goto unlock;
2859 }
2860
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002861 cmd->cmd_complete = addr_cmd_complete;
2862
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002863 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002864 dc.reason = 0x13; /* Remote User Terminated Connection */
2865 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2866 if (err < 0)
2867 mgmt_pending_remove(cmd);
2868
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002869unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002870 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002871 return err;
2872}
2873
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002874static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002875 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002876{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002877 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002878 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002879 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002880 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002881 int err;
2882
2883 BT_DBG("");
2884
Johan Hedberg06a63b12013-01-20 14:27:21 +02002885 memset(&rp, 0, sizeof(rp));
2886 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2887 rp.addr.type = cp->addr.type;
2888
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002889 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002890 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2891 MGMT_STATUS_INVALID_PARAMS,
2892 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002893
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002894 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002895
2896 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002897 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2898 MGMT_STATUS_NOT_POWERED, &rp,
2899 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002900 goto failed;
2901 }
2902
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002903 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002904 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2905 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002906 goto failed;
2907 }
2908
Andre Guedes591f47f2012-04-24 21:02:49 -03002909 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002910 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2911 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002912 else
2913 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002914
Vishal Agarwalf9607272012-06-13 05:32:43 +05302915 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002916 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2917 MGMT_STATUS_NOT_CONNECTED, &rp,
2918 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002919 goto failed;
2920 }
2921
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002922 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002923 if (!cmd) {
2924 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002925 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002926 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002927
Johan Hedbergf5818c22014-12-05 13:36:02 +02002928 cmd->cmd_complete = generic_cmd_complete;
2929
Johan Hedberge3f2f922014-08-18 20:33:33 +03002930 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002931 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002932 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002933
2934failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002935 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002936 return err;
2937}
2938
Andre Guedes57c14772012-04-24 21:02:50 -03002939static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002940{
2941 switch (link_type) {
2942 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002943 switch (addr_type) {
2944 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002945 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002946
Johan Hedberg48264f02011-11-09 13:58:58 +02002947 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002948 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002949 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002950 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002951
Johan Hedberg4c659c32011-11-07 23:13:39 +02002952 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002953 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002954 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002955 }
2956}
2957
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002958static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2959 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002960{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002961 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002962 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002963 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002964 int err;
2965 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002966
2967 BT_DBG("");
2968
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002969 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002970
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002971 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002972 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
2973 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002974 goto unlock;
2975 }
2976
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002977 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002978 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2979 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002980 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002981 }
2982
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002983 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002984 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002985 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002986 err = -ENOMEM;
2987 goto unlock;
2988 }
2989
Johan Hedberg2784eb42011-01-21 13:56:35 +02002990 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002991 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002992 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2993 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002994 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002995 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002996 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002997 continue;
2998 i++;
2999 }
3000
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003001 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003002
Johan Hedberg4c659c32011-11-07 23:13:39 +02003003 /* Recalculate length in case of filtered SCO connections, etc */
3004 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02003005
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003006 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
3007 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003008
Johan Hedberga38528f2011-01-22 06:46:43 +02003009 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003010
3011unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003012 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003013 return err;
3014}
3015
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003016static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003017 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003018{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003019 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003020 int err;
3021
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003022 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003023 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003024 if (!cmd)
3025 return -ENOMEM;
3026
Johan Hedbergd8457692012-02-17 14:24:57 +02003027 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003028 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003029 if (err < 0)
3030 mgmt_pending_remove(cmd);
3031
3032 return err;
3033}
3034
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003035static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003036 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003037{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003038 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003039 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003040 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003041 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003042 int err;
3043
3044 BT_DBG("");
3045
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003046 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003047
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003048 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003049 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3050 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003051 goto failed;
3052 }
3053
Johan Hedbergd8457692012-02-17 14:24:57 +02003054 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003055 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003056 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3057 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003058 goto failed;
3059 }
3060
3061 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02003062 struct mgmt_cp_pin_code_neg_reply ncp;
3063
3064 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003065
3066 BT_ERR("PIN code is not 16 bytes long");
3067
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003068 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003069 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02003070 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3071 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003072
3073 goto failed;
3074 }
3075
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03003076 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03003077 if (!cmd) {
3078 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003079 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03003080 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02003081
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003082 cmd->cmd_complete = addr_cmd_complete;
3083
Johan Hedbergd8457692012-02-17 14:24:57 +02003084 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003085 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02003086 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003087
3088 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
3089 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03003090 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003091
3092failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003093 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003094 return err;
3095}
3096
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003097static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
3098 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003099{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003100 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003101
3102 BT_DBG("");
3103
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003104 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003105 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
3106 MGMT_STATUS_INVALID_PARAMS, NULL, 0);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003107
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003108 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003109
3110 hdev->io_capability = cp->io_capability;
3111
3112 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003113 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003114
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003115 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003116
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003117 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
3118 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003119}
3120
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003121static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003122{
3123 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003124 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003125
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003126 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03003127 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
3128 continue;
3129
Johan Hedberge9a416b2011-02-19 12:05:56 -03003130 if (cmd->user_data != conn)
3131 continue;
3132
3133 return cmd;
3134 }
3135
3136 return NULL;
3137}
3138
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003139static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003140{
3141 struct mgmt_rp_pair_device rp;
3142 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02003143 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003144
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02003145 bacpy(&rp.addr.bdaddr, &conn->dst);
3146 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003147
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003148 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
3149 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003150
3151 /* So we don't get further callbacks for this connection */
3152 conn->connect_cfm_cb = NULL;
3153 conn->security_cfm_cb = NULL;
3154 conn->disconn_cfm_cb = NULL;
3155
David Herrmann76a68ba2013-04-06 20:28:37 +02003156 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00003157
3158 /* The device is paired so there is no need to remove
3159 * its connection parameters anymore.
3160 */
3161 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02003162
3163 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02003164
3165 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003166}
3167
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003168void mgmt_smp_complete(struct hci_conn *conn, bool complete)
3169{
3170 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003171 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003172
3173 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003174 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02003175 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02003176 mgmt_pending_remove(cmd);
3177 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003178}
3179
Johan Hedberge9a416b2011-02-19 12:05:56 -03003180static void pairing_complete_cb(struct hci_conn *conn, u8 status)
3181{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003182 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003183
3184 BT_DBG("status %u", status);
3185
Johan Hedberg56e5cb82011-11-08 20:40:16 +02003186 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003187 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02003188 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02003189 return;
3190 }
3191
3192 cmd->cmd_complete(cmd, mgmt_status(status));
3193 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003194}
3195
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003196static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303197{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003198 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303199
3200 BT_DBG("status %u", status);
3201
3202 if (!status)
3203 return;
3204
3205 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003206 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303207 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02003208 return;
3209 }
3210
3211 cmd->cmd_complete(cmd, mgmt_status(status));
3212 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303213}
3214
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003215static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003216 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003217{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003218 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02003219 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003220 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003221 u8 sec_level, auth_type;
3222 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003223 int err;
3224
3225 BT_DBG("");
3226
Szymon Jancf950a30e2013-01-18 12:48:07 +01003227 memset(&rp, 0, sizeof(rp));
3228 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3229 rp.addr.type = cp->addr.type;
3230
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003231 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003232 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3233 MGMT_STATUS_INVALID_PARAMS,
3234 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003235
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003236 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003237 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3238 MGMT_STATUS_INVALID_PARAMS,
3239 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003240
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003241 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003242
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003243 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003244 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3245 MGMT_STATUS_NOT_POWERED, &rp,
3246 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003247 goto unlock;
3248 }
3249
Johan Hedberg55e76b32015-03-10 22:34:40 +02003250 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
3251 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3252 MGMT_STATUS_ALREADY_PAIRED, &rp,
3253 sizeof(rp));
3254 goto unlock;
3255 }
3256
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03003257 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02003258 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003259
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003260 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03003261 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
3262 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003263 } else {
3264 u8 addr_type;
3265
3266 /* Convert from L2CAP channel address type to HCI address type
3267 */
3268 if (cp->addr.type == BDADDR_LE_PUBLIC)
3269 addr_type = ADDR_LE_DEV_PUBLIC;
3270 else
3271 addr_type = ADDR_LE_DEV_RANDOM;
3272
Marcel Holtmann7c264b12014-06-30 12:34:40 +02003273 /* When pairing a new device, it is expected to remember
3274 * this device for future connections. Adding the connection
3275 * parameter information ahead of time allows tracking
3276 * of the slave preferred values and will speed up any
3277 * further connection establishment.
3278 *
3279 * If connection parameters already exist, then they
3280 * will be kept and this function does nothing.
3281 */
3282 hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
3283
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003284 conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type,
Johan Hedberge804d252014-07-16 11:42:28 +03003285 sec_level, HCI_LE_CONN_TIMEOUT,
3286 HCI_ROLE_MASTER);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003287 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003288
Ville Tervo30e76272011-02-22 16:10:53 -03003289 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003290 int status;
3291
3292 if (PTR_ERR(conn) == -EBUSY)
3293 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01003294 else if (PTR_ERR(conn) == -EOPNOTSUPP)
3295 status = MGMT_STATUS_NOT_SUPPORTED;
3296 else if (PTR_ERR(conn) == -ECONNREFUSED)
3297 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003298 else
3299 status = MGMT_STATUS_CONNECT_FAILED;
3300
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003301 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3302 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003303 goto unlock;
3304 }
3305
3306 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02003307 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003308 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3309 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003310 goto unlock;
3311 }
3312
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003313 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003314 if (!cmd) {
3315 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02003316 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003317 goto unlock;
3318 }
3319
Johan Hedberg04ab2742014-12-05 13:36:04 +02003320 cmd->cmd_complete = pairing_complete;
3321
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003322 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003323 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003324 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003325 conn->security_cfm_cb = pairing_complete_cb;
3326 conn->disconn_cfm_cb = pairing_complete_cb;
3327 } else {
3328 conn->connect_cfm_cb = le_pairing_complete_cb;
3329 conn->security_cfm_cb = le_pairing_complete_cb;
3330 conn->disconn_cfm_cb = le_pairing_complete_cb;
3331 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003332
Johan Hedberge9a416b2011-02-19 12:05:56 -03003333 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003334 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003335
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003336 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003337 hci_conn_security(conn, sec_level, auth_type, true)) {
3338 cmd->cmd_complete(cmd, 0);
3339 mgmt_pending_remove(cmd);
3340 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003341
3342 err = 0;
3343
3344unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003345 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003346 return err;
3347}
3348
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003349static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3350 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003351{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003352 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003353 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003354 struct hci_conn *conn;
3355 int err;
3356
3357 BT_DBG("");
3358
Johan Hedberg28424702012-02-02 04:02:29 +02003359 hci_dev_lock(hdev);
3360
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003361 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003362 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3363 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003364 goto unlock;
3365 }
3366
Johan Hedberg28424702012-02-02 04:02:29 +02003367 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
3368 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003369 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3370 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003371 goto unlock;
3372 }
3373
3374 conn = cmd->user_data;
3375
3376 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003377 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3378 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003379 goto unlock;
3380 }
3381
Johan Hedberga511b352014-12-11 21:45:45 +02003382 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3383 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003384
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003385 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3386 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003387unlock:
3388 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003389 return err;
3390}
3391
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003392static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003393 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003394 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003395{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003396 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003397 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003398 int err;
3399
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003400 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003401
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003402 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003403 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3404 MGMT_STATUS_NOT_POWERED, addr,
3405 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003406 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003407 }
3408
Johan Hedberg1707c602013-03-15 17:07:15 -05003409 if (addr->type == BDADDR_BREDR)
3410 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003411 else
Johan Hedberg1707c602013-03-15 17:07:15 -05003412 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08003413
Johan Hedberg272d90d2012-02-09 15:26:12 +02003414 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003415 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3416 MGMT_STATUS_NOT_CONNECTED, addr,
3417 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003418 goto done;
3419 }
3420
Johan Hedberg1707c602013-03-15 17:07:15 -05003421 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003422 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003423 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003424 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3425 MGMT_STATUS_SUCCESS, addr,
3426 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003427 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003428 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3429 MGMT_STATUS_FAILED, addr,
3430 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003431
Brian Gix47c15e22011-11-16 13:53:14 -08003432 goto done;
3433 }
3434
Johan Hedberg1707c602013-03-15 17:07:15 -05003435 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003436 if (!cmd) {
3437 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003438 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003439 }
3440
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003441 cmd->cmd_complete = addr_cmd_complete;
3442
Brian Gix0df4c182011-11-16 13:53:13 -08003443 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003444 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3445 struct hci_cp_user_passkey_reply cp;
3446
Johan Hedberg1707c602013-03-15 17:07:15 -05003447 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003448 cp.passkey = passkey;
3449 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3450 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003451 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3452 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003453
Johan Hedberga664b5b2011-02-19 12:06:02 -03003454 if (err < 0)
3455 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003456
Brian Gix0df4c182011-11-16 13:53:13 -08003457done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003458 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003459 return err;
3460}
3461
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303462static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3463 void *data, u16 len)
3464{
3465 struct mgmt_cp_pin_code_neg_reply *cp = data;
3466
3467 BT_DBG("");
3468
Johan Hedberg1707c602013-03-15 17:07:15 -05003469 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303470 MGMT_OP_PIN_CODE_NEG_REPLY,
3471 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3472}
3473
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003474static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3475 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003476{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003477 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003478
3479 BT_DBG("");
3480
3481 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003482 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3483 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003484
Johan Hedberg1707c602013-03-15 17:07:15 -05003485 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003486 MGMT_OP_USER_CONFIRM_REPLY,
3487 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003488}
3489
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003490static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003491 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003492{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003493 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003494
3495 BT_DBG("");
3496
Johan Hedberg1707c602013-03-15 17:07:15 -05003497 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003498 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3499 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003500}
3501
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003502static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3503 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003504{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003505 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003506
3507 BT_DBG("");
3508
Johan Hedberg1707c602013-03-15 17:07:15 -05003509 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003510 MGMT_OP_USER_PASSKEY_REPLY,
3511 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003512}
3513
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003514static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003515 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003516{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003517 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003518
3519 BT_DBG("");
3520
Johan Hedberg1707c602013-03-15 17:07:15 -05003521 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003522 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3523 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003524}
3525
Johan Hedberg13928972013-03-15 17:07:00 -05003526static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003527{
Johan Hedberg13928972013-03-15 17:07:00 -05003528 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003529 struct hci_cp_write_local_name cp;
3530
Johan Hedberg13928972013-03-15 17:07:00 -05003531 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003532
Johan Hedberg890ea892013-03-15 17:06:52 -05003533 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003534}
3535
Marcel Holtmann1904a852015-01-11 13:50:44 -08003536static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003537{
3538 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003539 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003540
3541 BT_DBG("status 0x%02x", status);
3542
3543 hci_dev_lock(hdev);
3544
3545 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
3546 if (!cmd)
3547 goto unlock;
3548
3549 cp = cmd->param;
3550
3551 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003552 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3553 mgmt_status(status));
Johan Hedberg13928972013-03-15 17:07:00 -05003554 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003555 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3556 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003557
3558 mgmt_pending_remove(cmd);
3559
3560unlock:
3561 hci_dev_unlock(hdev);
3562}
3563
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003564static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003565 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003566{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003567 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003568 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003569 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003570 int err;
3571
3572 BT_DBG("");
3573
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003574 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003575
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003576 /* If the old values are the same as the new ones just return a
3577 * direct command complete event.
3578 */
3579 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3580 !memcmp(hdev->short_name, cp->short_name,
3581 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003582 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3583 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003584 goto failed;
3585 }
3586
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003587 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003588
Johan Hedbergb5235a62012-02-21 14:32:24 +02003589 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003590 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003591
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003592 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3593 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003594 if (err < 0)
3595 goto failed;
3596
3597 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003598 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003599
Johan Hedbergb5235a62012-02-21 14:32:24 +02003600 goto failed;
3601 }
3602
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003603 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003604 if (!cmd) {
3605 err = -ENOMEM;
3606 goto failed;
3607 }
3608
Johan Hedberg13928972013-03-15 17:07:00 -05003609 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3610
Johan Hedberg890ea892013-03-15 17:06:52 -05003611 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003612
3613 if (lmp_bredr_capable(hdev)) {
3614 update_name(&req);
3615 update_eir(&req);
3616 }
3617
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003618 /* The name is stored in the scan response data and so
3619 * no need to udpate the advertising data here.
3620 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003621 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003622 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003623
Johan Hedberg13928972013-03-15 17:07:00 -05003624 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003625 if (err < 0)
3626 mgmt_pending_remove(cmd);
3627
3628failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003629 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003630 return err;
3631}
3632
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003633static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003634 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003635{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003636 struct mgmt_pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01003637 int err;
3638
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003639 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003640
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003641 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003642
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003643 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003644 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3645 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003646 goto unlock;
3647 }
3648
Andre Guedes9a1a1992012-07-24 15:03:48 -03003649 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003650 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3651 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003652 goto unlock;
3653 }
3654
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003655 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003656 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3657 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003658 goto unlock;
3659 }
3660
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003661 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003662 if (!cmd) {
3663 err = -ENOMEM;
3664 goto unlock;
3665 }
3666
Johan Hedberg710f11c2014-05-26 11:21:22 +03003667 if (bredr_sc_enabled(hdev))
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003668 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
3669 0, NULL);
3670 else
3671 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3672
Szymon Jancc35938b2011-03-22 13:12:21 +01003673 if (err < 0)
3674 mgmt_pending_remove(cmd);
3675
3676unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003677 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003678 return err;
3679}
3680
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003681static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003682 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003683{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003684 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003685 int err;
3686
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003687 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003688
Johan Hedberg5d57e792015-01-23 10:10:38 +02003689 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003690 return mgmt_cmd_complete(sk, hdev->id,
3691 MGMT_OP_ADD_REMOTE_OOB_DATA,
3692 MGMT_STATUS_INVALID_PARAMS,
3693 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003694
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003695 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003696
Marcel Holtmannec109112014-01-10 02:07:30 -08003697 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3698 struct mgmt_cp_add_remote_oob_data *cp = data;
3699 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003700
Johan Hedbergc19a4952014-11-17 20:52:19 +02003701 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003702 err = mgmt_cmd_complete(sk, hdev->id,
3703 MGMT_OP_ADD_REMOTE_OOB_DATA,
3704 MGMT_STATUS_INVALID_PARAMS,
3705 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003706 goto unlock;
3707 }
3708
Marcel Holtmannec109112014-01-10 02:07:30 -08003709 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003710 cp->addr.type, cp->hash,
3711 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003712 if (err < 0)
3713 status = MGMT_STATUS_FAILED;
3714 else
3715 status = MGMT_STATUS_SUCCESS;
3716
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003717 err = mgmt_cmd_complete(sk, hdev->id,
3718 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3719 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003720 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3721 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003722 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003723 u8 status;
3724
Johan Hedberg86df9202014-10-26 20:52:27 +01003725 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003726 /* Enforce zero-valued 192-bit parameters as
3727 * long as legacy SMP OOB isn't implemented.
3728 */
3729 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3730 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003731 err = mgmt_cmd_complete(sk, hdev->id,
3732 MGMT_OP_ADD_REMOTE_OOB_DATA,
3733 MGMT_STATUS_INVALID_PARAMS,
3734 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003735 goto unlock;
3736 }
3737
Johan Hedberg86df9202014-10-26 20:52:27 +01003738 rand192 = NULL;
3739 hash192 = NULL;
3740 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003741 /* In case one of the P-192 values is set to zero,
3742 * then just disable OOB data for P-192.
3743 */
3744 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3745 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3746 rand192 = NULL;
3747 hash192 = NULL;
3748 } else {
3749 rand192 = cp->rand192;
3750 hash192 = cp->hash192;
3751 }
3752 }
3753
3754 /* In case one of the P-256 values is set to zero, then just
3755 * disable OOB data for P-256.
3756 */
3757 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3758 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3759 rand256 = NULL;
3760 hash256 = NULL;
3761 } else {
3762 rand256 = cp->rand256;
3763 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003764 }
3765
Johan Hedberg81328d52014-10-26 20:33:47 +01003766 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003767 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003768 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003769 if (err < 0)
3770 status = MGMT_STATUS_FAILED;
3771 else
3772 status = MGMT_STATUS_SUCCESS;
3773
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003774 err = mgmt_cmd_complete(sk, hdev->id,
3775 MGMT_OP_ADD_REMOTE_OOB_DATA,
3776 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003777 } else {
3778 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003779 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3780 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003781 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003782
Johan Hedbergc19a4952014-11-17 20:52:19 +02003783unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003784 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003785 return err;
3786}
3787
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003788static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003789 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003790{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003791 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003792 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003793 int err;
3794
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003795 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003796
Johan Hedbergc19a4952014-11-17 20:52:19 +02003797 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003798 return mgmt_cmd_complete(sk, hdev->id,
3799 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3800 MGMT_STATUS_INVALID_PARAMS,
3801 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003802
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003803 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003804
Johan Hedbergeedbd582014-11-15 09:34:23 +02003805 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3806 hci_remote_oob_data_clear(hdev);
3807 status = MGMT_STATUS_SUCCESS;
3808 goto done;
3809 }
3810
Johan Hedberg6928a922014-10-26 20:46:09 +01003811 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003812 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003813 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003814 else
Szymon Janca6785be2012-12-13 15:11:21 +01003815 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003816
Johan Hedbergeedbd582014-11-15 09:34:23 +02003817done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003818 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3819 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003820
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003821 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003822 return err;
3823}
3824
Marcel Holtmann80190442014-12-04 11:36:36 +01003825static bool trigger_discovery(struct hci_request *req, u8 *status)
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003826{
Marcel Holtmann80190442014-12-04 11:36:36 +01003827 struct hci_dev *hdev = req->hdev;
3828 struct hci_cp_le_set_scan_param param_cp;
3829 struct hci_cp_le_set_scan_enable enable_cp;
3830 struct hci_cp_inquiry inq_cp;
3831 /* General inquiry access code (GIAC) */
3832 u8 lap[3] = { 0x33, 0x8b, 0x9e };
3833 u8 own_addr_type;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003834 int err;
3835
Marcel Holtmann80190442014-12-04 11:36:36 +01003836 switch (hdev->discovery.type) {
3837 case DISCOV_TYPE_BREDR:
3838 *status = mgmt_bredr_support(hdev);
3839 if (*status)
3840 return false;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003841
Marcel Holtmann80190442014-12-04 11:36:36 +01003842 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3843 *status = MGMT_STATUS_BUSY;
3844 return false;
3845 }
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003846
Marcel Holtmann80190442014-12-04 11:36:36 +01003847 hci_inquiry_cache_flush(hdev);
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003848
Marcel Holtmann80190442014-12-04 11:36:36 +01003849 memset(&inq_cp, 0, sizeof(inq_cp));
3850 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
3851 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
3852 hci_req_add(req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
3853 break;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003854
Marcel Holtmann80190442014-12-04 11:36:36 +01003855 case DISCOV_TYPE_LE:
3856 case DISCOV_TYPE_INTERLEAVED:
3857 *status = mgmt_le_support(hdev);
3858 if (*status)
3859 return false;
3860
3861 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003862 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmann80190442014-12-04 11:36:36 +01003863 *status = MGMT_STATUS_NOT_SUPPORTED;
3864 return false;
3865 }
3866
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003867 if (hci_dev_test_flag(hdev, HCI_LE_ADV)) {
Marcel Holtmann80190442014-12-04 11:36:36 +01003868 /* Don't let discovery abort an outgoing
3869 * connection attempt that's using directed
3870 * advertising.
3871 */
3872 if (hci_conn_hash_lookup_state(hdev, LE_LINK,
3873 BT_CONNECT)) {
3874 *status = MGMT_STATUS_REJECTED;
3875 return false;
3876 }
3877
3878 disable_advertising(req);
3879 }
3880
3881 /* If controller is scanning, it means the background scanning
3882 * is running. Thus, we should temporarily stop it in order to
3883 * set the discovery scanning parameters.
3884 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003885 if (hci_dev_test_flag(hdev, HCI_LE_SCAN))
Marcel Holtmann80190442014-12-04 11:36:36 +01003886 hci_req_add_le_scan_disable(req);
3887
3888 memset(&param_cp, 0, sizeof(param_cp));
3889
3890 /* All active scans will be done with either a resolvable
3891 * private address (when privacy feature has been enabled)
Marcel Holtmann9437d2e2014-12-07 20:13:17 +01003892 * or non-resolvable private address.
Marcel Holtmann80190442014-12-04 11:36:36 +01003893 */
3894 err = hci_update_random_address(req, true, &own_addr_type);
3895 if (err < 0) {
3896 *status = MGMT_STATUS_FAILED;
3897 return false;
3898 }
3899
3900 param_cp.type = LE_SCAN_ACTIVE;
3901 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3902 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
3903 param_cp.own_address_type = own_addr_type;
3904 hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3905 &param_cp);
3906
3907 memset(&enable_cp, 0, sizeof(enable_cp));
3908 enable_cp.enable = LE_SCAN_ENABLE;
3909 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3910 hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3911 &enable_cp);
3912 break;
3913
3914 default:
3915 *status = MGMT_STATUS_INVALID_PARAMS;
3916 return false;
3917 }
3918
3919 return true;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003920}
3921
Marcel Holtmann1904a852015-01-11 13:50:44 -08003922static void start_discovery_complete(struct hci_dev *hdev, u8 status,
3923 u16 opcode)
Andre Guedes7c307722013-04-30 15:29:28 -03003924{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003925 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003926 unsigned long timeout;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003927
Andre Guedes7c307722013-04-30 15:29:28 -03003928 BT_DBG("status %d", status);
3929
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003930 hci_dev_lock(hdev);
3931
3932 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01003933 if (!cmd)
3934 cmd = mgmt_pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
3935
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003936 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02003937 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003938 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03003939 }
3940
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003941 if (status) {
3942 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3943 goto unlock;
3944 }
3945
Andre Guedes7c307722013-04-30 15:29:28 -03003946 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
Andre Guedes7c307722013-04-30 15:29:28 -03003947
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08003948 /* If the scan involves LE scan, pick proper timeout to schedule
3949 * hdev->le_scan_disable that will stop it.
3950 */
Andre Guedes7c307722013-04-30 15:29:28 -03003951 switch (hdev->discovery.type) {
3952 case DISCOV_TYPE_LE:
Lukasz Rymanowski3d5a76f2014-03-27 20:55:21 +01003953 timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003954 break;
Andre Guedes7c307722013-04-30 15:29:28 -03003955 case DISCOV_TYPE_INTERLEAVED:
Lukasz Rymanowskib9a7a612014-03-27 20:55:20 +01003956 timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
Andre Guedes7c307722013-04-30 15:29:28 -03003957 break;
Andre Guedes7c307722013-04-30 15:29:28 -03003958 case DISCOV_TYPE_BREDR:
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003959 timeout = 0;
Andre Guedes7c307722013-04-30 15:29:28 -03003960 break;
Andre Guedes7c307722013-04-30 15:29:28 -03003961 default:
3962 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003963 timeout = 0;
3964 break;
Andre Guedes7c307722013-04-30 15:29:28 -03003965 }
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003966
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08003967 if (timeout) {
3968 /* When service discovery is used and the controller has
3969 * a strict duplicate filter, it is important to remember
3970 * the start and duration of the scan. This is required
3971 * for restarting scanning during the discovery phase.
3972 */
3973 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER,
3974 &hdev->quirks) &&
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08003975 hdev->discovery.result_filtering) {
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08003976 hdev->discovery.scan_start = jiffies;
3977 hdev->discovery.scan_duration = timeout;
3978 }
3979
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003980 queue_delayed_work(hdev->workqueue,
3981 &hdev->le_scan_disable, timeout);
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08003982 }
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01003983
Marcel Holtmann11e6e252014-12-04 11:36:35 +01003984unlock:
3985 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03003986}
3987
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003988static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003989 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003990{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003991 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003992 struct mgmt_pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003993 struct hci_request req;
Marcel Holtmann80190442014-12-04 11:36:36 +01003994 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003995 int err;
3996
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003997 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003998
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003999 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004000
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004001 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004002 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4003 MGMT_STATUS_NOT_POWERED,
4004 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02004005 goto failed;
4006 }
4007
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004008 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004009 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004010 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4011 MGMT_STATUS_BUSY, &cp->type,
4012 sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03004013 goto failed;
4014 }
4015
Johan Hedberg2922a942014-12-05 13:36:06 +02004016 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004017 if (!cmd) {
4018 err = -ENOMEM;
4019 goto failed;
4020 }
4021
Johan Hedberg2922a942014-12-05 13:36:06 +02004022 cmd->cmd_complete = generic_cmd_complete;
4023
Marcel Holtmann22078802014-12-05 11:45:22 +01004024 /* Clear the discovery filter first to free any previously
4025 * allocated memory for the UUID list.
4026 */
4027 hci_discovery_filter_clear(hdev);
4028
Andre Guedes4aab14e2012-02-17 20:39:36 -03004029 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01004030 hdev->discovery.report_invalid_rssi = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03004031
Andre Guedes7c307722013-04-30 15:29:28 -03004032 hci_req_init(&req, hdev);
4033
Marcel Holtmann80190442014-12-04 11:36:36 +01004034 if (!trigger_discovery(&req, &status)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004035 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4036 status, &cp->type, sizeof(cp->type));
Johan Hedberg04106752013-01-10 14:54:09 +02004037 mgmt_pending_remove(cmd);
4038 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004039 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004040
Andre Guedes7c307722013-04-30 15:29:28 -03004041 err = hci_req_run(&req, start_discovery_complete);
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004042 if (err < 0) {
Johan Hedberg14a53662011-04-27 10:29:56 -04004043 mgmt_pending_remove(cmd);
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004044 goto failed;
4045 }
4046
4047 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04004048
4049failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004050 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004051 return err;
4052}
4053
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004054static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4055 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004056{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004057 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4058 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004059}
4060
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004061static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4062 void *data, u16 len)
4063{
4064 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004065 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004066 struct hci_request req;
4067 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4068 u16 uuid_count, expected_len;
4069 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004070 int err;
4071
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004072 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004073
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004074 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004075
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004076 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004077 err = mgmt_cmd_complete(sk, hdev->id,
4078 MGMT_OP_START_SERVICE_DISCOVERY,
4079 MGMT_STATUS_NOT_POWERED,
4080 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004081 goto failed;
4082 }
4083
4084 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004085 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004086 err = mgmt_cmd_complete(sk, hdev->id,
4087 MGMT_OP_START_SERVICE_DISCOVERY,
4088 MGMT_STATUS_BUSY, &cp->type,
4089 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004090 goto failed;
4091 }
4092
4093 uuid_count = __le16_to_cpu(cp->uuid_count);
4094 if (uuid_count > max_uuid_count) {
4095 BT_ERR("service_discovery: too big uuid_count value %u",
4096 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004097 err = mgmt_cmd_complete(sk, hdev->id,
4098 MGMT_OP_START_SERVICE_DISCOVERY,
4099 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4100 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004101 goto failed;
4102 }
4103
4104 expected_len = sizeof(*cp) + uuid_count * 16;
4105 if (expected_len != len) {
4106 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
4107 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004108 err = mgmt_cmd_complete(sk, hdev->id,
4109 MGMT_OP_START_SERVICE_DISCOVERY,
4110 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4111 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004112 goto failed;
4113 }
4114
4115 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02004116 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004117 if (!cmd) {
4118 err = -ENOMEM;
4119 goto failed;
4120 }
4121
Johan Hedberg2922a942014-12-05 13:36:06 +02004122 cmd->cmd_complete = service_discovery_cmd_complete;
4123
Marcel Holtmann22078802014-12-05 11:45:22 +01004124 /* Clear the discovery filter first to free any previously
4125 * allocated memory for the UUID list.
4126 */
4127 hci_discovery_filter_clear(hdev);
4128
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004129 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004130 hdev->discovery.type = cp->type;
4131 hdev->discovery.rssi = cp->rssi;
4132 hdev->discovery.uuid_count = uuid_count;
4133
4134 if (uuid_count > 0) {
4135 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4136 GFP_KERNEL);
4137 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004138 err = mgmt_cmd_complete(sk, hdev->id,
4139 MGMT_OP_START_SERVICE_DISCOVERY,
4140 MGMT_STATUS_FAILED,
4141 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004142 mgmt_pending_remove(cmd);
4143 goto failed;
4144 }
4145 }
4146
4147 hci_req_init(&req, hdev);
4148
4149 if (!trigger_discovery(&req, &status)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004150 err = mgmt_cmd_complete(sk, hdev->id,
4151 MGMT_OP_START_SERVICE_DISCOVERY,
4152 status, &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004153 mgmt_pending_remove(cmd);
4154 goto failed;
4155 }
4156
4157 err = hci_req_run(&req, start_discovery_complete);
4158 if (err < 0) {
4159 mgmt_pending_remove(cmd);
4160 goto failed;
4161 }
4162
4163 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
4164
4165failed:
4166 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004167 return err;
4168}
4169
Marcel Holtmann1904a852015-01-11 13:50:44 -08004170static void stop_discovery_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004171{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004172 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004173
Andre Guedes0e05bba2013-04-30 15:29:33 -03004174 BT_DBG("status %d", status);
4175
4176 hci_dev_lock(hdev);
4177
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004178 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
4179 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004180 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004181 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004182 }
4183
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004184 if (!status)
4185 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004186
Andre Guedes0e05bba2013-04-30 15:29:33 -03004187 hci_dev_unlock(hdev);
4188}
4189
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004190static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004191 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004192{
Johan Hedbergd9306502012-02-20 23:25:18 +02004193 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004194 struct mgmt_pending_cmd *cmd;
Andre Guedes0e05bba2013-04-30 15:29:33 -03004195 struct hci_request req;
Johan Hedberg14a53662011-04-27 10:29:56 -04004196 int err;
4197
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004198 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004199
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004200 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004201
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004202 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004203 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4204 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4205 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004206 goto unlock;
4207 }
4208
4209 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004210 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4211 MGMT_STATUS_INVALID_PARAMS,
4212 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004213 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004214 }
4215
Johan Hedberg2922a942014-12-05 13:36:06 +02004216 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004217 if (!cmd) {
4218 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004219 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004220 }
4221
Johan Hedberg2922a942014-12-05 13:36:06 +02004222 cmd->cmd_complete = generic_cmd_complete;
4223
Andre Guedes0e05bba2013-04-30 15:29:33 -03004224 hci_req_init(&req, hdev);
4225
Johan Hedberg21a60d32014-06-10 14:05:58 +03004226 hci_stop_discovery(&req);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004227
Johan Hedberg21a60d32014-06-10 14:05:58 +03004228 err = hci_req_run(&req, stop_discovery_complete);
4229 if (!err) {
4230 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004231 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004232 }
4233
Johan Hedberg21a60d32014-06-10 14:05:58 +03004234 mgmt_pending_remove(cmd);
4235
4236 /* If no HCI commands were sent we're done */
4237 if (err == -ENODATA) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004238 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
4239 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg21a60d32014-06-10 14:05:58 +03004240 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
4241 }
Johan Hedberg14a53662011-04-27 10:29:56 -04004242
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004243unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004244 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004245 return err;
4246}
4247
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004248static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004249 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004250{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004251 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004252 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004253 int err;
4254
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004255 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004256
Johan Hedberg561aafb2012-01-04 13:31:59 +02004257 hci_dev_lock(hdev);
4258
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004259 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004260 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4261 MGMT_STATUS_FAILED, &cp->addr,
4262 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004263 goto failed;
4264 }
4265
Johan Hedberga198e7b2012-02-17 14:27:06 +02004266 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004267 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004268 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4269 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4270 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004271 goto failed;
4272 }
4273
4274 if (cp->name_known) {
4275 e->name_state = NAME_KNOWN;
4276 list_del(&e->list);
4277 } else {
4278 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02004279 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004280 }
4281
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004282 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4283 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004284
4285failed:
4286 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004287 return err;
4288}
4289
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004290static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004291 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004292{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004293 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004294 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004295 int err;
4296
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004297 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004298
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004299 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004300 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4301 MGMT_STATUS_INVALID_PARAMS,
4302 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004303
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004304 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004305
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004306 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4307 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004308 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004309 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004310 goto done;
4311 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004312
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004313 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4314 sk);
4315 status = MGMT_STATUS_SUCCESS;
4316
4317done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004318 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4319 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004320
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004321 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004322
4323 return err;
4324}
4325
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004326static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004327 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004328{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004329 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004330 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004331 int err;
4332
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004333 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004334
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004335 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004336 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4337 MGMT_STATUS_INVALID_PARAMS,
4338 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004339
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004340 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004341
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004342 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4343 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004344 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004345 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004346 goto done;
4347 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004348
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004349 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4350 sk);
4351 status = MGMT_STATUS_SUCCESS;
4352
4353done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004354 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4355 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004356
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004357 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004358
4359 return err;
4360}
4361
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004362static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4363 u16 len)
4364{
4365 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004366 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004367 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004368 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004369
4370 BT_DBG("%s", hdev->name);
4371
Szymon Jancc72d4b82012-03-16 16:02:57 +01004372 source = __le16_to_cpu(cp->source);
4373
4374 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004375 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4376 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004377
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004378 hci_dev_lock(hdev);
4379
Szymon Jancc72d4b82012-03-16 16:02:57 +01004380 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004381 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4382 hdev->devid_product = __le16_to_cpu(cp->product);
4383 hdev->devid_version = __le16_to_cpu(cp->version);
4384
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004385 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4386 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004387
Johan Hedberg890ea892013-03-15 17:06:52 -05004388 hci_req_init(&req, hdev);
4389 update_eir(&req);
4390 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004391
4392 hci_dev_unlock(hdev);
4393
4394 return err;
4395}
4396
Marcel Holtmann1904a852015-01-11 13:50:44 -08004397static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4398 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004399{
4400 struct cmd_lookup match = { NULL, hdev };
4401
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304402 hci_dev_lock(hdev);
4403
Johan Hedberg4375f102013-09-25 13:26:10 +03004404 if (status) {
4405 u8 mgmt_err = mgmt_status(status);
4406
4407 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4408 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304409 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004410 }
4411
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004412 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004413 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004414 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004415 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004416
Johan Hedberg4375f102013-09-25 13:26:10 +03004417 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4418 &match);
4419
4420 new_settings(hdev, match.sk);
4421
4422 if (match.sk)
4423 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304424
4425unlock:
4426 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004427}
4428
Marcel Holtmann21b51872013-10-10 09:47:53 -07004429static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4430 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004431{
4432 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004433 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004434 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004435 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004436 int err;
4437
4438 BT_DBG("request for %s", hdev->name);
4439
Johan Hedberge6fe7982013-10-02 15:45:22 +03004440 status = mgmt_le_support(hdev);
4441 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004442 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4443 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004444
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004445 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004446 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4447 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004448
4449 hci_dev_lock(hdev);
4450
4451 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004452
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004453 /* The following conditions are ones which mean that we should
4454 * not do any HCI communication but directly send a mgmt
4455 * response to user space (after toggling the flag if
4456 * necessary).
4457 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004458 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004459 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4460 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004461 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004462 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004463 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004464 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004465
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004466 if (cp->val) {
4467 changed = !test_and_set_bit(HCI_ADVERTISING,
4468 &hdev->dev_flags);
4469 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004470 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004471 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004472 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004473 } else {
4474 changed = test_and_clear_bit(HCI_ADVERTISING,
4475 &hdev->dev_flags);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004476 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004477 }
4478
4479 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4480 if (err < 0)
4481 goto unlock;
4482
4483 if (changed)
4484 err = new_settings(hdev, sk);
4485
4486 goto unlock;
4487 }
4488
4489 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4490 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004491 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4492 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004493 goto unlock;
4494 }
4495
4496 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4497 if (!cmd) {
4498 err = -ENOMEM;
4499 goto unlock;
4500 }
4501
4502 hci_req_init(&req, hdev);
4503
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004504 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004505 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004506 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004507 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004508
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004509 if (val)
4510 enable_advertising(&req);
4511 else
4512 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03004513
4514 err = hci_req_run(&req, set_advertising_complete);
4515 if (err < 0)
4516 mgmt_pending_remove(cmd);
4517
4518unlock:
4519 hci_dev_unlock(hdev);
4520 return err;
4521}
4522
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004523static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4524 void *data, u16 len)
4525{
4526 struct mgmt_cp_set_static_address *cp = data;
4527 int err;
4528
4529 BT_DBG("%s", hdev->name);
4530
Marcel Holtmann62af4442013-10-02 22:10:32 -07004531 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004532 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4533 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004534
4535 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004536 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4537 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004538
4539 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4540 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004541 return mgmt_cmd_status(sk, hdev->id,
4542 MGMT_OP_SET_STATIC_ADDRESS,
4543 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004544
4545 /* Two most significant bits shall be set */
4546 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004547 return mgmt_cmd_status(sk, hdev->id,
4548 MGMT_OP_SET_STATIC_ADDRESS,
4549 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004550 }
4551
4552 hci_dev_lock(hdev);
4553
4554 bacpy(&hdev->static_addr, &cp->bdaddr);
4555
Marcel Holtmann93690c22015-03-06 10:11:21 -08004556 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4557 if (err < 0)
4558 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004559
Marcel Holtmann93690c22015-03-06 10:11:21 -08004560 err = new_settings(hdev, sk);
4561
4562unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004563 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004564 return err;
4565}
4566
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004567static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4568 void *data, u16 len)
4569{
4570 struct mgmt_cp_set_scan_params *cp = data;
4571 __u16 interval, window;
4572 int err;
4573
4574 BT_DBG("%s", hdev->name);
4575
4576 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004577 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4578 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004579
4580 interval = __le16_to_cpu(cp->interval);
4581
4582 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004583 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4584 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004585
4586 window = __le16_to_cpu(cp->window);
4587
4588 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004589 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4590 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004591
Marcel Holtmann899e1072013-10-14 09:55:32 -07004592 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004593 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4594 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004595
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004596 hci_dev_lock(hdev);
4597
4598 hdev->le_scan_interval = interval;
4599 hdev->le_scan_window = window;
4600
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004601 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4602 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004603
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004604 /* If background scan is running, restart it so new parameters are
4605 * loaded.
4606 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004607 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004608 hdev->discovery.state == DISCOVERY_STOPPED) {
4609 struct hci_request req;
4610
4611 hci_req_init(&req, hdev);
4612
4613 hci_req_add_le_scan_disable(&req);
4614 hci_req_add_le_passive_scan(&req);
4615
4616 hci_req_run(&req, NULL);
4617 }
4618
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004619 hci_dev_unlock(hdev);
4620
4621 return err;
4622}
4623
Marcel Holtmann1904a852015-01-11 13:50:44 -08004624static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4625 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004626{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004627 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004628
4629 BT_DBG("status 0x%02x", status);
4630
4631 hci_dev_lock(hdev);
4632
4633 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4634 if (!cmd)
4635 goto unlock;
4636
4637 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004638 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4639 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004640 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004641 struct mgmt_mode *cp = cmd->param;
4642
4643 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004644 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004645 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004646 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004647
Johan Hedberg33e38b32013-03-15 17:07:05 -05004648 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4649 new_settings(hdev, cmd->sk);
4650 }
4651
4652 mgmt_pending_remove(cmd);
4653
4654unlock:
4655 hci_dev_unlock(hdev);
4656}
4657
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004658static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004659 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004660{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004661 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004662 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004663 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004664 int err;
4665
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004666 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004667
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004668 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004669 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004670 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4671 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004672
Johan Hedberga7e80f22013-01-09 16:05:19 +02004673 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004674 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4675 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004676
Antti Julkuf6422ec2011-06-22 13:11:56 +03004677 hci_dev_lock(hdev);
4678
Johan Hedberg05cbf292013-03-15 17:07:07 -05004679 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004680 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4681 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004682 goto unlock;
4683 }
4684
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004685 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004686 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4687 hdev);
4688 goto unlock;
4689 }
4690
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004691 if (!hdev_is_powered(hdev)) {
4692 change_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
4693 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4694 hdev);
4695 new_settings(hdev, sk);
4696 goto unlock;
4697 }
4698
Johan Hedberg33e38b32013-03-15 17:07:05 -05004699 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4700 data, len);
4701 if (!cmd) {
4702 err = -ENOMEM;
4703 goto unlock;
4704 }
4705
4706 hci_req_init(&req, hdev);
4707
Johan Hedberg406d7802013-03-15 17:07:09 -05004708 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004709
4710 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004711 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004712 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4713 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004714 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004715 }
4716
Johan Hedberg33e38b32013-03-15 17:07:05 -05004717unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004718 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004719
Antti Julkuf6422ec2011-06-22 13:11:56 +03004720 return err;
4721}
4722
Marcel Holtmann1904a852015-01-11 13:50:44 -08004723static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004724{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004725 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004726
4727 BT_DBG("status 0x%02x", status);
4728
4729 hci_dev_lock(hdev);
4730
4731 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
4732 if (!cmd)
4733 goto unlock;
4734
4735 if (status) {
4736 u8 mgmt_err = mgmt_status(status);
4737
4738 /* We need to restore the flag if related HCI commands
4739 * failed.
4740 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004741 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004742
Johan Hedberga69e8372015-03-06 21:08:53 +02004743 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004744 } else {
4745 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4746 new_settings(hdev, cmd->sk);
4747 }
4748
4749 mgmt_pending_remove(cmd);
4750
4751unlock:
4752 hci_dev_unlock(hdev);
4753}
4754
4755static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4756{
4757 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004758 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004759 struct hci_request req;
4760 int err;
4761
4762 BT_DBG("request for %s", hdev->name);
4763
4764 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004765 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4766 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004767
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004768 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004769 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4770 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004771
4772 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004773 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4774 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004775
4776 hci_dev_lock(hdev);
4777
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004778 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004779 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4780 goto unlock;
4781 }
4782
4783 if (!hdev_is_powered(hdev)) {
4784 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004785 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4786 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4787 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4788 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4789 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004790 }
4791
4792 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4793
4794 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4795 if (err < 0)
4796 goto unlock;
4797
4798 err = new_settings(hdev, sk);
4799 goto unlock;
4800 }
4801
4802 /* Reject disabling when powered on */
4803 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004804 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4805 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004806 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004807 } else {
4808 /* When configuring a dual-mode controller to operate
4809 * with LE only and using a static address, then switching
4810 * BR/EDR back on is not allowed.
4811 *
4812 * Dual-mode controllers shall operate with the public
4813 * address as its identity address for BR/EDR and LE. So
4814 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004815 *
4816 * The same restrictions applies when secure connections
4817 * has been enabled. For BR/EDR this is a controller feature
4818 * while for LE it is a host stack feature. This means that
4819 * switching BR/EDR back on when secure connections has been
4820 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004821 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004822 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004823 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004824 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004825 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4826 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004827 goto unlock;
4828 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004829 }
4830
4831 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004832 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4833 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004834 goto unlock;
4835 }
4836
4837 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4838 if (!cmd) {
4839 err = -ENOMEM;
4840 goto unlock;
4841 }
4842
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004843 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03004844 * generates the correct flags.
4845 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004846 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004847
4848 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004849
Johan Hedberg432df052014-08-01 11:13:31 +03004850 write_fast_connectable(&req, false);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02004851 __hci_update_page_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004852
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004853 /* Since only the advertising data flags will change, there
4854 * is no need to update the scan response data.
4855 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004856 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004857
Johan Hedberg0663ca22013-10-02 13:43:14 +03004858 err = hci_req_run(&req, set_bredr_complete);
4859 if (err < 0)
4860 mgmt_pending_remove(cmd);
4861
4862unlock:
4863 hci_dev_unlock(hdev);
4864 return err;
4865}
4866
Johan Hedberga1443f52015-01-23 15:42:46 +02004867static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4868{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004869 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004870 struct mgmt_mode *cp;
4871
4872 BT_DBG("%s status %u", hdev->name, status);
4873
4874 hci_dev_lock(hdev);
4875
4876 cmd = mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
4877 if (!cmd)
4878 goto unlock;
4879
4880 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004881 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4882 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004883 goto remove;
4884 }
4885
4886 cp = cmd->param;
4887
4888 switch (cp->val) {
4889 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004890 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4891 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004892 break;
4893 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004894 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004895 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004896 break;
4897 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004898 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4899 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004900 break;
4901 }
4902
4903 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4904 new_settings(hdev, cmd->sk);
4905
4906remove:
4907 mgmt_pending_remove(cmd);
4908unlock:
4909 hci_dev_unlock(hdev);
4910}
4911
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004912static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4913 void *data, u16 len)
4914{
4915 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004916 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004917 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004918 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004919 int err;
4920
4921 BT_DBG("request for %s", hdev->name);
4922
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004923 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004924 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004925 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4926 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004927
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004928 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02004929 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004930 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004931 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4932 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08004933
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004934 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004935 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004936 MGMT_STATUS_INVALID_PARAMS);
4937
4938 hci_dev_lock(hdev);
4939
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08004940 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004941 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004942 bool changed;
4943
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004944 if (cp->val) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004945 changed = !test_and_set_bit(HCI_SC_ENABLED,
4946 &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004947 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004948 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004949 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004950 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004951 } else {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004952 changed = test_and_clear_bit(HCI_SC_ENABLED,
4953 &hdev->dev_flags);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004954 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004955 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004956
4957 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4958 if (err < 0)
4959 goto failed;
4960
4961 if (changed)
4962 err = new_settings(hdev, sk);
4963
4964 goto failed;
4965 }
4966
4967 if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004968 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4969 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004970 goto failed;
4971 }
4972
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004973 val = !!cp->val;
4974
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004975 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
4976 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004977 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4978 goto failed;
4979 }
4980
4981 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4982 if (!cmd) {
4983 err = -ENOMEM;
4984 goto failed;
4985 }
4986
Johan Hedberga1443f52015-01-23 15:42:46 +02004987 hci_req_init(&req, hdev);
4988 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
4989 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004990 if (err < 0) {
4991 mgmt_pending_remove(cmd);
4992 goto failed;
4993 }
4994
4995failed:
4996 hci_dev_unlock(hdev);
4997 return err;
4998}
4999
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005000static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
5001 void *data, u16 len)
5002{
5003 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03005004 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005005 int err;
5006
5007 BT_DBG("request for %s", hdev->name);
5008
Johan Hedbergb97109792014-06-24 14:00:28 +03005009 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005010 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
5011 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005012
5013 hci_dev_lock(hdev);
5014
5015 if (cp->val)
Johan Hedberg0663b292014-06-24 13:15:50 +03005016 changed = !test_and_set_bit(HCI_KEEP_DEBUG_KEYS,
5017 &hdev->dev_flags);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005018 else
Johan Hedberg0663b292014-06-24 13:15:50 +03005019 changed = test_and_clear_bit(HCI_KEEP_DEBUG_KEYS,
5020 &hdev->dev_flags);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005021
Johan Hedbergb97109792014-06-24 14:00:28 +03005022 if (cp->val == 0x02)
5023 use_changed = !test_and_set_bit(HCI_USE_DEBUG_KEYS,
5024 &hdev->dev_flags);
5025 else
5026 use_changed = test_and_clear_bit(HCI_USE_DEBUG_KEYS,
5027 &hdev->dev_flags);
5028
5029 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005030 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03005031 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
5032 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
5033 sizeof(mode), &mode);
5034 }
5035
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005036 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
5037 if (err < 0)
5038 goto unlock;
5039
5040 if (changed)
5041 err = new_settings(hdev, sk);
5042
5043unlock:
5044 hci_dev_unlock(hdev);
5045 return err;
5046}
5047
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005048static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5049 u16 len)
5050{
5051 struct mgmt_cp_set_privacy *cp = cp_data;
5052 bool changed;
5053 int err;
5054
5055 BT_DBG("request for %s", hdev->name);
5056
5057 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005058 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5059 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005060
5061 if (cp->privacy != 0x00 && cp->privacy != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005062 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5063 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005064
5065 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005066 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5067 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005068
5069 hci_dev_lock(hdev);
5070
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005071 /* If user space supports this command it is also expected to
5072 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
5073 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005074 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005075
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005076 if (cp->privacy) {
5077 changed = !test_and_set_bit(HCI_PRIVACY, &hdev->dev_flags);
5078 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005079 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005080 } else {
5081 changed = test_and_clear_bit(HCI_PRIVACY, &hdev->dev_flags);
5082 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005083 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005084 }
5085
5086 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
5087 if (err < 0)
5088 goto unlock;
5089
5090 if (changed)
5091 err = new_settings(hdev, sk);
5092
5093unlock:
5094 hci_dev_unlock(hdev);
5095 return err;
5096}
5097
Johan Hedberg41edf162014-02-18 10:19:35 +02005098static bool irk_is_valid(struct mgmt_irk_info *irk)
5099{
5100 switch (irk->addr.type) {
5101 case BDADDR_LE_PUBLIC:
5102 return true;
5103
5104 case BDADDR_LE_RANDOM:
5105 /* Two most significant bits shall be set */
5106 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5107 return false;
5108 return true;
5109 }
5110
5111 return false;
5112}
5113
5114static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5115 u16 len)
5116{
5117 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005118 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5119 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005120 u16 irk_count, expected_len;
5121 int i, err;
5122
5123 BT_DBG("request for %s", hdev->name);
5124
5125 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005126 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5127 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005128
5129 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005130 if (irk_count > max_irk_count) {
5131 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005132 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5133 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005134 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005135
5136 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
5137 if (expected_len != len) {
5138 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02005139 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005140 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5141 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005142 }
5143
5144 BT_DBG("%s irk_count %u", hdev->name, irk_count);
5145
5146 for (i = 0; i < irk_count; i++) {
5147 struct mgmt_irk_info *key = &cp->irks[i];
5148
5149 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005150 return mgmt_cmd_status(sk, hdev->id,
5151 MGMT_OP_LOAD_IRKS,
5152 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005153 }
5154
5155 hci_dev_lock(hdev);
5156
5157 hci_smp_irks_clear(hdev);
5158
5159 for (i = 0; i < irk_count; i++) {
5160 struct mgmt_irk_info *irk = &cp->irks[i];
5161 u8 addr_type;
5162
5163 if (irk->addr.type == BDADDR_LE_PUBLIC)
5164 addr_type = ADDR_LE_DEV_PUBLIC;
5165 else
5166 addr_type = ADDR_LE_DEV_RANDOM;
5167
5168 hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
5169 BDADDR_ANY);
5170 }
5171
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005172 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005173
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005174 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005175
5176 hci_dev_unlock(hdev);
5177
5178 return err;
5179}
5180
Johan Hedberg3f706b72013-01-20 14:27:16 +02005181static bool ltk_is_valid(struct mgmt_ltk_info *key)
5182{
5183 if (key->master != 0x00 && key->master != 0x01)
5184 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005185
5186 switch (key->addr.type) {
5187 case BDADDR_LE_PUBLIC:
5188 return true;
5189
5190 case BDADDR_LE_RANDOM:
5191 /* Two most significant bits shall be set */
5192 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5193 return false;
5194 return true;
5195 }
5196
5197 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005198}
5199
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005200static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005201 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005202{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005203 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005204 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5205 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005206 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005207 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005208
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005209 BT_DBG("request for %s", hdev->name);
5210
5211 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005212 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5213 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005214
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005215 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005216 if (key_count > max_key_count) {
5217 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005218 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5219 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005220 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005221
5222 expected_len = sizeof(*cp) + key_count *
5223 sizeof(struct mgmt_ltk_info);
5224 if (expected_len != len) {
5225 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02005226 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005227 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5228 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005229 }
5230
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005231 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005232
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005233 for (i = 0; i < key_count; i++) {
5234 struct mgmt_ltk_info *key = &cp->keys[i];
5235
Johan Hedberg3f706b72013-01-20 14:27:16 +02005236 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005237 return mgmt_cmd_status(sk, hdev->id,
5238 MGMT_OP_LOAD_LONG_TERM_KEYS,
5239 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005240 }
5241
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005242 hci_dev_lock(hdev);
5243
5244 hci_smp_ltks_clear(hdev);
5245
5246 for (i = 0; i < key_count; i++) {
5247 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedbergd7b25452014-05-23 13:19:53 +03005248 u8 type, addr_type, authenticated;
Marcel Holtmann79d95a12013-10-13 03:57:38 -07005249
5250 if (key->addr.type == BDADDR_LE_PUBLIC)
5251 addr_type = ADDR_LE_DEV_PUBLIC;
5252 else
5253 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005254
Johan Hedberg61b43352014-05-29 19:36:53 +03005255 switch (key->type) {
5256 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005257 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005258 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005259 break;
5260 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005261 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005262 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005263 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005264 case MGMT_LTK_P256_UNAUTH:
5265 authenticated = 0x00;
5266 type = SMP_LTK_P256;
5267 break;
5268 case MGMT_LTK_P256_AUTH:
5269 authenticated = 0x01;
5270 type = SMP_LTK_P256;
5271 break;
5272 case MGMT_LTK_P256_DEBUG:
5273 authenticated = 0x00;
5274 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03005275 default:
5276 continue;
5277 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005278
Johan Hedberg35d70272014-02-19 14:57:47 +02005279 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type,
Johan Hedbergd7b25452014-05-23 13:19:53 +03005280 authenticated, key->val, key->enc_size, key->ediv,
Johan Hedberg35d70272014-02-19 14:57:47 +02005281 key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005282 }
5283
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005284 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005285 NULL, 0);
5286
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005287 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005288
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005289 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005290}
5291
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005292static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005293{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005294 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005295 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005296 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005297
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005298 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005299
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005300 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005301 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005302 rp.tx_power = conn->tx_power;
5303 rp.max_tx_power = conn->max_tx_power;
5304 } else {
5305 rp.rssi = HCI_RSSI_INVALID;
5306 rp.tx_power = HCI_TX_POWER_INVALID;
5307 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005308 }
5309
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005310 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5311 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005312
5313 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005314 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005315
5316 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005317}
5318
Marcel Holtmann1904a852015-01-11 13:50:44 -08005319static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5320 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005321{
5322 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005323 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005324 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005325 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005326 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005327
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005328 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005329
5330 hci_dev_lock(hdev);
5331
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005332 /* Commands sent in request are either Read RSSI or Read Transmit Power
5333 * Level so we check which one was last sent to retrieve connection
5334 * handle. Both commands have handle as first parameter so it's safe to
5335 * cast data on the same command struct.
5336 *
5337 * First command sent is always Read RSSI and we fail only if it fails.
5338 * In other case we simply override error to indicate success as we
5339 * already remembered if TX power value is actually valid.
5340 */
5341 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5342 if (!cp) {
5343 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005344 status = MGMT_STATUS_SUCCESS;
5345 } else {
5346 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005347 }
5348
5349 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005350 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005351 goto unlock;
5352 }
5353
5354 handle = __le16_to_cpu(cp->handle);
5355 conn = hci_conn_hash_lookup_handle(hdev, handle);
5356 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005357 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005358 goto unlock;
5359 }
5360
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005361 cmd = mgmt_pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
5362 if (!cmd)
5363 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005364
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005365 cmd->cmd_complete(cmd, status);
5366 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005367
5368unlock:
5369 hci_dev_unlock(hdev);
5370}
5371
5372static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5373 u16 len)
5374{
5375 struct mgmt_cp_get_conn_info *cp = data;
5376 struct mgmt_rp_get_conn_info rp;
5377 struct hci_conn *conn;
5378 unsigned long conn_info_age;
5379 int err = 0;
5380
5381 BT_DBG("%s", hdev->name);
5382
5383 memset(&rp, 0, sizeof(rp));
5384 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5385 rp.addr.type = cp->addr.type;
5386
5387 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005388 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5389 MGMT_STATUS_INVALID_PARAMS,
5390 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005391
5392 hci_dev_lock(hdev);
5393
5394 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005395 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5396 MGMT_STATUS_NOT_POWERED, &rp,
5397 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005398 goto unlock;
5399 }
5400
5401 if (cp->addr.type == BDADDR_BREDR)
5402 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5403 &cp->addr.bdaddr);
5404 else
5405 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5406
5407 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005408 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5409 MGMT_STATUS_NOT_CONNECTED, &rp,
5410 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005411 goto unlock;
5412 }
5413
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005414 if (mgmt_pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005415 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5416 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005417 goto unlock;
5418 }
5419
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005420 /* To avoid client trying to guess when to poll again for information we
5421 * calculate conn info age as random value between min/max set in hdev.
5422 */
5423 conn_info_age = hdev->conn_info_min_age +
5424 prandom_u32_max(hdev->conn_info_max_age -
5425 hdev->conn_info_min_age);
5426
5427 /* Query controller to refresh cached values if they are too old or were
5428 * never read.
5429 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005430 if (time_after(jiffies, conn->conn_info_timestamp +
5431 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005432 !conn->conn_info_timestamp) {
5433 struct hci_request req;
5434 struct hci_cp_read_tx_power req_txp_cp;
5435 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005436 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005437
5438 hci_req_init(&req, hdev);
5439 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5440 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5441 &req_rssi_cp);
5442
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005443 /* For LE links TX power does not change thus we don't need to
5444 * query for it once value is known.
5445 */
5446 if (!bdaddr_type_is_le(cp->addr.type) ||
5447 conn->tx_power == HCI_TX_POWER_INVALID) {
5448 req_txp_cp.handle = cpu_to_le16(conn->handle);
5449 req_txp_cp.type = 0x00;
5450 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5451 sizeof(req_txp_cp), &req_txp_cp);
5452 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005453
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005454 /* Max TX power needs to be read only once per connection */
5455 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5456 req_txp_cp.handle = cpu_to_le16(conn->handle);
5457 req_txp_cp.type = 0x01;
5458 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5459 sizeof(req_txp_cp), &req_txp_cp);
5460 }
5461
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005462 err = hci_req_run(&req, conn_info_refresh_complete);
5463 if (err < 0)
5464 goto unlock;
5465
5466 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5467 data, len);
5468 if (!cmd) {
5469 err = -ENOMEM;
5470 goto unlock;
5471 }
5472
5473 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005474 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005475 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005476
5477 conn->conn_info_timestamp = jiffies;
5478 } else {
5479 /* Cache is valid, just reply with values cached in hci_conn */
5480 rp.rssi = conn->rssi;
5481 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005482 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005483
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005484 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5485 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005486 }
5487
5488unlock:
5489 hci_dev_unlock(hdev);
5490 return err;
5491}
5492
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005493static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005494{
5495 struct hci_conn *conn = cmd->user_data;
5496 struct mgmt_rp_get_clock_info rp;
5497 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005498 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005499
5500 memset(&rp, 0, sizeof(rp));
5501 memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
5502
5503 if (status)
5504 goto complete;
5505
5506 hdev = hci_dev_get(cmd->index);
5507 if (hdev) {
5508 rp.local_clock = cpu_to_le32(hdev->clock);
5509 hci_dev_put(hdev);
5510 }
5511
5512 if (conn) {
5513 rp.piconet_clock = cpu_to_le32(conn->clock);
5514 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5515 }
5516
5517complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005518 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5519 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005520
5521 if (conn) {
5522 hci_conn_drop(conn);
5523 hci_conn_put(conn);
5524 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005525
5526 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005527}
5528
Marcel Holtmann1904a852015-01-11 13:50:44 -08005529static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005530{
Johan Hedberg95868422014-06-28 17:54:07 +03005531 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_conn *conn;
5534
5535 BT_DBG("%s status %u", hdev->name, status);
5536
5537 hci_dev_lock(hdev);
5538
5539 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5540 if (!hci_cp)
5541 goto unlock;
5542
5543 if (hci_cp->which) {
5544 u16 handle = __le16_to_cpu(hci_cp->handle);
5545 conn = hci_conn_hash_lookup_handle(hdev, handle);
5546 } else {
5547 conn = NULL;
5548 }
5549
5550 cmd = mgmt_pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
5551 if (!cmd)
5552 goto unlock;
5553
Johan Hedberg69487372014-12-05 13:36:07 +02005554 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005555 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005556
5557unlock:
5558 hci_dev_unlock(hdev);
5559}
5560
5561static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5562 u16 len)
5563{
5564 struct mgmt_cp_get_clock_info *cp = data;
5565 struct mgmt_rp_get_clock_info rp;
5566 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005567 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005568 struct hci_request req;
5569 struct hci_conn *conn;
5570 int err;
5571
5572 BT_DBG("%s", hdev->name);
5573
5574 memset(&rp, 0, sizeof(rp));
5575 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5576 rp.addr.type = cp->addr.type;
5577
5578 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005579 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5580 MGMT_STATUS_INVALID_PARAMS,
5581 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005582
5583 hci_dev_lock(hdev);
5584
5585 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005586 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5587 MGMT_STATUS_NOT_POWERED, &rp,
5588 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005589 goto unlock;
5590 }
5591
5592 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5593 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5594 &cp->addr.bdaddr);
5595 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005596 err = mgmt_cmd_complete(sk, hdev->id,
5597 MGMT_OP_GET_CLOCK_INFO,
5598 MGMT_STATUS_NOT_CONNECTED,
5599 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005600 goto unlock;
5601 }
5602 } else {
5603 conn = NULL;
5604 }
5605
5606 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5607 if (!cmd) {
5608 err = -ENOMEM;
5609 goto unlock;
5610 }
5611
Johan Hedberg69487372014-12-05 13:36:07 +02005612 cmd->cmd_complete = clock_info_cmd_complete;
5613
Johan Hedberg95868422014-06-28 17:54:07 +03005614 hci_req_init(&req, hdev);
5615
5616 memset(&hci_cp, 0, sizeof(hci_cp));
5617 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5618
5619 if (conn) {
5620 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005621 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005622
5623 hci_cp.handle = cpu_to_le16(conn->handle);
5624 hci_cp.which = 0x01; /* Piconet clock */
5625 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5626 }
5627
5628 err = hci_req_run(&req, get_clock_info_complete);
5629 if (err < 0)
5630 mgmt_pending_remove(cmd);
5631
5632unlock:
5633 hci_dev_unlock(hdev);
5634 return err;
5635}
5636
Johan Hedberg5a154e62014-12-19 22:26:02 +02005637static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5638{
5639 struct hci_conn *conn;
5640
5641 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5642 if (!conn)
5643 return false;
5644
5645 if (conn->dst_type != type)
5646 return false;
5647
5648 if (conn->state != BT_CONNECTED)
5649 return false;
5650
5651 return true;
5652}
5653
5654/* This function requires the caller holds hdev->lock */
5655static int hci_conn_params_set(struct hci_request *req, bdaddr_t *addr,
5656 u8 addr_type, u8 auto_connect)
5657{
5658 struct hci_dev *hdev = req->hdev;
5659 struct hci_conn_params *params;
5660
5661 params = hci_conn_params_add(hdev, addr, addr_type);
5662 if (!params)
5663 return -EIO;
5664
5665 if (params->auto_connect == auto_connect)
5666 return 0;
5667
5668 list_del_init(&params->action);
5669
5670 switch (auto_connect) {
5671 case HCI_AUTO_CONN_DISABLED:
5672 case HCI_AUTO_CONN_LINK_LOSS:
5673 __hci_update_background_scan(req);
5674 break;
5675 case HCI_AUTO_CONN_REPORT:
5676 list_add(&params->action, &hdev->pend_le_reports);
5677 __hci_update_background_scan(req);
5678 break;
5679 case HCI_AUTO_CONN_DIRECT:
5680 case HCI_AUTO_CONN_ALWAYS:
5681 if (!is_connected(hdev, addr, addr_type)) {
5682 list_add(&params->action, &hdev->pend_le_conns);
5683 __hci_update_background_scan(req);
5684 }
5685 break;
5686 }
5687
5688 params->auto_connect = auto_connect;
5689
5690 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5691 auto_connect);
5692
5693 return 0;
5694}
5695
Marcel Holtmann8afef092014-06-29 22:28:34 +02005696static void device_added(struct sock *sk, struct hci_dev *hdev,
5697 bdaddr_t *bdaddr, u8 type, u8 action)
5698{
5699 struct mgmt_ev_device_added ev;
5700
5701 bacpy(&ev.addr.bdaddr, bdaddr);
5702 ev.addr.type = type;
5703 ev.action = action;
5704
5705 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5706}
5707
Marcel Holtmann1904a852015-01-11 13:50:44 -08005708static void add_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg5a154e62014-12-19 22:26:02 +02005709{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005710 struct mgmt_pending_cmd *cmd;
Johan Hedberg5a154e62014-12-19 22:26:02 +02005711
5712 BT_DBG("status 0x%02x", status);
5713
5714 hci_dev_lock(hdev);
5715
5716 cmd = mgmt_pending_find(MGMT_OP_ADD_DEVICE, hdev);
5717 if (!cmd)
5718 goto unlock;
5719
5720 cmd->cmd_complete(cmd, mgmt_status(status));
5721 mgmt_pending_remove(cmd);
5722
5723unlock:
5724 hci_dev_unlock(hdev);
5725}
5726
Marcel Holtmann2faade52014-06-29 19:44:03 +02005727static int add_device(struct sock *sk, struct hci_dev *hdev,
5728 void *data, u16 len)
5729{
5730 struct mgmt_cp_add_device *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005731 struct mgmt_pending_cmd *cmd;
Johan Hedberg5a154e62014-12-19 22:26:02 +02005732 struct hci_request req;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005733 u8 auto_conn, addr_type;
5734 int err;
5735
5736 BT_DBG("%s", hdev->name);
5737
Johan Hedberg66593582014-07-09 12:59:14 +03005738 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005739 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005740 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5741 MGMT_STATUS_INVALID_PARAMS,
5742 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005743
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005744 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005745 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5746 MGMT_STATUS_INVALID_PARAMS,
5747 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005748
Johan Hedberg5a154e62014-12-19 22:26:02 +02005749 hci_req_init(&req, hdev);
5750
Marcel Holtmann2faade52014-06-29 19:44:03 +02005751 hci_dev_lock(hdev);
5752
Johan Hedberg5a154e62014-12-19 22:26:02 +02005753 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_DEVICE, hdev, data, len);
5754 if (!cmd) {
5755 err = -ENOMEM;
5756 goto unlock;
5757 }
5758
5759 cmd->cmd_complete = addr_cmd_complete;
5760
Johan Hedberg66593582014-07-09 12:59:14 +03005761 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005762 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005763 if (cp->action != 0x01) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005764 err = cmd->cmd_complete(cmd,
5765 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005766 mgmt_pending_remove(cmd);
Johan Hedberg66593582014-07-09 12:59:14 +03005767 goto unlock;
5768 }
5769
5770 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5771 cp->addr.type);
5772 if (err)
5773 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005774
Johan Hedberg5a154e62014-12-19 22:26:02 +02005775 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03005776
Johan Hedberg66593582014-07-09 12:59:14 +03005777 goto added;
5778 }
5779
Marcel Holtmann2faade52014-06-29 19:44:03 +02005780 if (cp->addr.type == BDADDR_LE_PUBLIC)
5781 addr_type = ADDR_LE_DEV_PUBLIC;
5782 else
5783 addr_type = ADDR_LE_DEV_RANDOM;
5784
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005785 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005786 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005787 else if (cp->action == 0x01)
5788 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005789 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005790 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005791
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005792 /* If the connection parameters don't exist for this device,
5793 * they will be created and configured with defaults.
5794 */
Johan Hedberg5a154e62014-12-19 22:26:02 +02005795 if (hci_conn_params_set(&req, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005796 auto_conn) < 0) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005797 err = cmd->cmd_complete(cmd, MGMT_STATUS_FAILED);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005798 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005799 goto unlock;
5800 }
5801
Johan Hedberg66593582014-07-09 12:59:14 +03005802added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005803 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5804
Johan Hedberg5a154e62014-12-19 22:26:02 +02005805 err = hci_req_run(&req, add_device_complete);
5806 if (err < 0) {
5807 /* ENODATA means no HCI commands were needed (e.g. if
5808 * the adapter is powered off).
5809 */
Johan Hedberg9df74652014-12-19 22:26:03 +02005810 if (err == -ENODATA)
5811 err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005812 mgmt_pending_remove(cmd);
5813 }
Marcel Holtmann2faade52014-06-29 19:44:03 +02005814
5815unlock:
5816 hci_dev_unlock(hdev);
5817 return err;
5818}
5819
Marcel Holtmann8afef092014-06-29 22:28:34 +02005820static void device_removed(struct sock *sk, struct hci_dev *hdev,
5821 bdaddr_t *bdaddr, u8 type)
5822{
5823 struct mgmt_ev_device_removed ev;
5824
5825 bacpy(&ev.addr.bdaddr, bdaddr);
5826 ev.addr.type = type;
5827
5828 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5829}
5830
Marcel Holtmann1904a852015-01-11 13:50:44 -08005831static void remove_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005832{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005833 struct mgmt_pending_cmd *cmd;
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005834
5835 BT_DBG("status 0x%02x", status);
5836
5837 hci_dev_lock(hdev);
5838
5839 cmd = mgmt_pending_find(MGMT_OP_REMOVE_DEVICE, hdev);
5840 if (!cmd)
5841 goto unlock;
5842
5843 cmd->cmd_complete(cmd, mgmt_status(status));
5844 mgmt_pending_remove(cmd);
5845
5846unlock:
5847 hci_dev_unlock(hdev);
5848}
5849
Marcel Holtmann2faade52014-06-29 19:44:03 +02005850static int remove_device(struct sock *sk, struct hci_dev *hdev,
5851 void *data, u16 len)
5852{
5853 struct mgmt_cp_remove_device *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005854 struct mgmt_pending_cmd *cmd;
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005855 struct hci_request req;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005856 int err;
5857
5858 BT_DBG("%s", hdev->name);
5859
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005860 hci_req_init(&req, hdev);
5861
Marcel Holtmann2faade52014-06-29 19:44:03 +02005862 hci_dev_lock(hdev);
5863
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005864 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_DEVICE, hdev, data, len);
5865 if (!cmd) {
5866 err = -ENOMEM;
5867 goto unlock;
5868 }
5869
5870 cmd->cmd_complete = addr_cmd_complete;
5871
Marcel Holtmann2faade52014-06-29 19:44:03 +02005872 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005873 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005874 u8 addr_type;
5875
Johan Hedberg66593582014-07-09 12:59:14 +03005876 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005877 err = cmd->cmd_complete(cmd,
5878 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005879 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005880 goto unlock;
5881 }
5882
Johan Hedberg66593582014-07-09 12:59:14 +03005883 if (cp->addr.type == BDADDR_BREDR) {
5884 err = hci_bdaddr_list_del(&hdev->whitelist,
5885 &cp->addr.bdaddr,
5886 cp->addr.type);
5887 if (err) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005888 err = cmd->cmd_complete(cmd,
5889 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005890 mgmt_pending_remove(cmd);
Johan Hedberg66593582014-07-09 12:59:14 +03005891 goto unlock;
5892 }
5893
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005894 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03005895
Johan Hedberg66593582014-07-09 12:59:14 +03005896 device_removed(sk, hdev, &cp->addr.bdaddr,
5897 cp->addr.type);
5898 goto complete;
5899 }
5900
Marcel Holtmann2faade52014-06-29 19:44:03 +02005901 if (cp->addr.type == BDADDR_LE_PUBLIC)
5902 addr_type = ADDR_LE_DEV_PUBLIC;
5903 else
5904 addr_type = ADDR_LE_DEV_RANDOM;
5905
Johan Hedbergc71593d2014-07-02 17:37:28 +03005906 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5907 addr_type);
5908 if (!params) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005909 err = cmd->cmd_complete(cmd,
5910 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005911 mgmt_pending_remove(cmd);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005912 goto unlock;
5913 }
5914
5915 if (params->auto_connect == HCI_AUTO_CONN_DISABLED) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005916 err = cmd->cmd_complete(cmd,
5917 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005918 mgmt_pending_remove(cmd);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005919 goto unlock;
5920 }
5921
Johan Hedbergd1dbf122014-07-04 16:17:23 +03005922 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005923 list_del(&params->list);
5924 kfree(params);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005925 __hci_update_background_scan(&req);
Marcel Holtmann8afef092014-06-29 22:28:34 +02005926
5927 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005928 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03005929 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03005930 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03005931
Marcel Holtmann2faade52014-06-29 19:44:03 +02005932 if (cp->addr.type) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005933 err = cmd->cmd_complete(cmd,
5934 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005935 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005936 goto unlock;
5937 }
5938
Johan Hedberg66593582014-07-09 12:59:14 +03005939 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
5940 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
5941 list_del(&b->list);
5942 kfree(b);
5943 }
5944
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005945 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03005946
Johan Hedberg19de0822014-07-06 13:06:51 +03005947 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
5948 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
5949 continue;
5950 device_removed(sk, hdev, &p->addr, p->addr_type);
5951 list_del(&p->action);
5952 list_del(&p->list);
5953 kfree(p);
5954 }
5955
5956 BT_DBG("All LE connection parameters were removed");
5957
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005958 __hci_update_background_scan(&req);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005959 }
5960
Johan Hedberg66593582014-07-09 12:59:14 +03005961complete:
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005962 err = hci_req_run(&req, remove_device_complete);
5963 if (err < 0) {
5964 /* ENODATA means no HCI commands were needed (e.g. if
5965 * the adapter is powered off).
5966 */
Johan Hedberg9df74652014-12-19 22:26:03 +02005967 if (err == -ENODATA)
5968 err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005969 mgmt_pending_remove(cmd);
5970 }
Marcel Holtmann2faade52014-06-29 19:44:03 +02005971
5972unlock:
5973 hci_dev_unlock(hdev);
5974 return err;
5975}
5976
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005977static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
5978 u16 len)
5979{
5980 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005981 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
5982 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005983 u16 param_count, expected_len;
5984 int i;
5985
5986 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005987 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5988 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005989
5990 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005991 if (param_count > max_param_count) {
5992 BT_ERR("load_conn_param: too big param_count value %u",
5993 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005994 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
5995 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005996 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03005997
5998 expected_len = sizeof(*cp) + param_count *
5999 sizeof(struct mgmt_conn_param);
6000 if (expected_len != len) {
6001 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
6002 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006003 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6004 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006005 }
6006
6007 BT_DBG("%s param_count %u", hdev->name, param_count);
6008
6009 hci_dev_lock(hdev);
6010
6011 hci_conn_params_clear_disabled(hdev);
6012
6013 for (i = 0; i < param_count; i++) {
6014 struct mgmt_conn_param *param = &cp->params[i];
6015 struct hci_conn_params *hci_param;
6016 u16 min, max, latency, timeout;
6017 u8 addr_type;
6018
6019 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
6020 param->addr.type);
6021
6022 if (param->addr.type == BDADDR_LE_PUBLIC) {
6023 addr_type = ADDR_LE_DEV_PUBLIC;
6024 } else if (param->addr.type == BDADDR_LE_RANDOM) {
6025 addr_type = ADDR_LE_DEV_RANDOM;
6026 } else {
6027 BT_ERR("Ignoring invalid connection parameters");
6028 continue;
6029 }
6030
6031 min = le16_to_cpu(param->min_interval);
6032 max = le16_to_cpu(param->max_interval);
6033 latency = le16_to_cpu(param->latency);
6034 timeout = le16_to_cpu(param->timeout);
6035
6036 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6037 min, max, latency, timeout);
6038
6039 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
6040 BT_ERR("Ignoring invalid connection parameters");
6041 continue;
6042 }
6043
6044 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
6045 addr_type);
6046 if (!hci_param) {
6047 BT_ERR("Failed to add connection parameters");
6048 continue;
6049 }
6050
6051 hci_param->conn_min_interval = min;
6052 hci_param->conn_max_interval = max;
6053 hci_param->conn_latency = latency;
6054 hci_param->supervision_timeout = timeout;
6055 }
6056
6057 hci_dev_unlock(hdev);
6058
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006059 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
6060 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006061}
6062
Marcel Holtmanndbece372014-07-04 18:11:55 +02006063static int set_external_config(struct sock *sk, struct hci_dev *hdev,
6064 void *data, u16 len)
6065{
6066 struct mgmt_cp_set_external_config *cp = data;
6067 bool changed;
6068 int err;
6069
6070 BT_DBG("%s", hdev->name);
6071
6072 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006073 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6074 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006075
6076 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006077 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6078 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006079
6080 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02006081 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6082 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006083
6084 hci_dev_lock(hdev);
6085
6086 if (cp->config)
6087 changed = !test_and_set_bit(HCI_EXT_CONFIGURED,
6088 &hdev->dev_flags);
6089 else
6090 changed = test_and_clear_bit(HCI_EXT_CONFIGURED,
6091 &hdev->dev_flags);
6092
6093 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
6094 if (err < 0)
6095 goto unlock;
6096
6097 if (!changed)
6098 goto unlock;
6099
Marcel Holtmannf4537c02014-07-04 19:06:23 +02006100 err = new_options(hdev, sk);
6101
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006102 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02006103 mgmt_index_removed(hdev);
Marcel Holtmannd603b762014-07-06 12:11:14 +02006104
6105 if (test_and_change_bit(HCI_UNCONFIGURED, &hdev->dev_flags)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006106 hci_dev_set_flag(hdev, HCI_CONFIG);
6107 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b762014-07-06 12:11:14 +02006108
6109 queue_work(hdev->req_workqueue, &hdev->power_on);
6110 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02006111 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b762014-07-06 12:11:14 +02006112 mgmt_index_added(hdev);
6113 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02006114 }
6115
6116unlock:
6117 hci_dev_unlock(hdev);
6118 return err;
6119}
6120
Marcel Holtmann9713c172014-07-06 12:11:15 +02006121static int set_public_address(struct sock *sk, struct hci_dev *hdev,
6122 void *data, u16 len)
6123{
6124 struct mgmt_cp_set_public_address *cp = data;
6125 bool changed;
6126 int err;
6127
6128 BT_DBG("%s", hdev->name);
6129
6130 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006131 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6132 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006133
6134 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02006135 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6136 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006137
6138 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02006139 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6140 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006141
6142 hci_dev_lock(hdev);
6143
6144 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
6145 bacpy(&hdev->public_addr, &cp->bdaddr);
6146
6147 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
6148 if (err < 0)
6149 goto unlock;
6150
6151 if (!changed)
6152 goto unlock;
6153
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006154 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006155 err = new_options(hdev, sk);
6156
6157 if (is_configured(hdev)) {
6158 mgmt_index_removed(hdev);
6159
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006160 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006161
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006162 hci_dev_set_flag(hdev, HCI_CONFIG);
6163 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006164
6165 queue_work(hdev->req_workqueue, &hdev->power_on);
6166 }
6167
6168unlock:
6169 hci_dev_unlock(hdev);
6170 return err;
6171}
6172
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006173static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006174 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006175 { read_version, MGMT_READ_VERSION_SIZE,
6176 HCI_MGMT_NO_HDEV },
6177 { read_commands, MGMT_READ_COMMANDS_SIZE,
6178 HCI_MGMT_NO_HDEV },
6179 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
6180 HCI_MGMT_NO_HDEV },
6181 { read_controller_info, MGMT_READ_INFO_SIZE, 0 },
6182 { set_powered, MGMT_SETTING_SIZE, 0 },
6183 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE, 0 },
6184 { set_connectable, MGMT_SETTING_SIZE, 0 },
6185 { set_fast_connectable, MGMT_SETTING_SIZE, 0 },
6186 { set_bondable, MGMT_SETTING_SIZE, 0 },
6187 { set_link_security, MGMT_SETTING_SIZE, 0 },
6188 { set_ssp, MGMT_SETTING_SIZE, 0 },
6189 { set_hs, MGMT_SETTING_SIZE, 0 },
6190 { set_le, MGMT_SETTING_SIZE, 0 },
6191 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE, 0 },
6192 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE, 0 },
6193 { add_uuid, MGMT_ADD_UUID_SIZE, 0 },
6194 { remove_uuid, MGMT_REMOVE_UUID_SIZE, 0 },
6195 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6196 HCI_MGMT_VAR_LEN },
6197 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6198 HCI_MGMT_VAR_LEN },
6199 { disconnect, MGMT_DISCONNECT_SIZE, 0 },
6200 { get_connections, MGMT_GET_CONNECTIONS_SIZE, 0 },
6201 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE, 0 },
6202 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE, 0 },
6203 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE, 0 },
6204 { pair_device, MGMT_PAIR_DEVICE_SIZE, 0 },
6205 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE, 0 },
6206 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE, 0 },
6207 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE, 0 },
6208 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE, 0 },
6209 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE, 0 },
6210 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE, 0 },
6211 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6212 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6213 HCI_MGMT_VAR_LEN },
6214 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE, 0 },
6215 { start_discovery, MGMT_START_DISCOVERY_SIZE, 0 },
6216 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE, 0 },
6217 { confirm_name, MGMT_CONFIRM_NAME_SIZE, 0 },
6218 { block_device, MGMT_BLOCK_DEVICE_SIZE, 0 },
6219 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE, 0 },
6220 { set_device_id, MGMT_SET_DEVICE_ID_SIZE, 0 },
6221 { set_advertising, MGMT_SETTING_SIZE, 0 },
6222 { set_bredr, MGMT_SETTING_SIZE, 0 },
6223 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE, 0 },
6224 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE, 0 },
6225 { set_secure_conn, MGMT_SETTING_SIZE, 0 },
6226 { set_debug_keys, MGMT_SETTING_SIZE, 0 },
6227 { set_privacy, MGMT_SET_PRIVACY_SIZE, 0 },
6228 { load_irks, MGMT_LOAD_IRKS_SIZE,
6229 HCI_MGMT_VAR_LEN },
6230 { get_conn_info, MGMT_GET_CONN_INFO_SIZE, 0 },
6231 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE, 0 },
6232 { add_device, MGMT_ADD_DEVICE_SIZE, 0 },
6233 { remove_device, MGMT_REMOVE_DEVICE_SIZE, 0 },
6234 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6235 HCI_MGMT_VAR_LEN },
6236 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
6237 HCI_MGMT_NO_HDEV },
6238 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
6239 HCI_MGMT_UNCONFIGURED },
6240 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6241 HCI_MGMT_UNCONFIGURED },
6242 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6243 HCI_MGMT_UNCONFIGURED },
6244 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6245 HCI_MGMT_VAR_LEN },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006246};
6247
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006248int mgmt_control(struct hci_mgmt_chan *chan, struct sock *sk,
6249 struct msghdr *msg, size_t msglen)
Johan Hedberg03811012010-12-08 00:21:06 +02006250{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03006251 void *buf;
6252 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02006253 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01006254 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006255 struct hci_dev *hdev = NULL;
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006256 const struct hci_mgmt_handler *handler;
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006257 bool var_len, no_hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02006258 int err;
6259
6260 BT_DBG("got %zu bytes", msglen);
6261
6262 if (msglen < sizeof(*hdr))
6263 return -EINVAL;
6264
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03006265 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02006266 if (!buf)
6267 return -ENOMEM;
6268
Al Viro6ce8e9c2014-04-06 21:25:44 -04006269 if (memcpy_from_msg(buf, msg, msglen)) {
Johan Hedberg03811012010-12-08 00:21:06 +02006270 err = -EFAULT;
6271 goto done;
6272 }
6273
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03006274 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07006275 opcode = __le16_to_cpu(hdr->opcode);
6276 index = __le16_to_cpu(hdr->index);
6277 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02006278
6279 if (len != msglen - sizeof(*hdr)) {
6280 err = -EINVAL;
6281 goto done;
6282 }
6283
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006284 if (opcode >= chan->handler_count ||
6285 chan->handlers[opcode].func == NULL) {
6286 BT_DBG("Unknown op %u", opcode);
Johan Hedberga69e8372015-03-06 21:08:53 +02006287 err = mgmt_cmd_status(sk, index, opcode,
6288 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006289 goto done;
6290 }
6291
6292 handler = &chan->handlers[opcode];
6293
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006294 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006295 hdev = hci_dev_get(index);
6296 if (!hdev) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006297 err = mgmt_cmd_status(sk, index, opcode,
6298 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006299 goto done;
6300 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07006301
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006302 if (hci_dev_test_flag(hdev, HCI_SETUP) ||
6303 hci_dev_test_flag(hdev, HCI_CONFIG) ||
6304 hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006305 err = mgmt_cmd_status(sk, index, opcode,
6306 MGMT_STATUS_INVALID_INDEX);
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07006307 goto done;
6308 }
Marcel Holtmann42a9bc142014-07-04 16:54:40 +02006309
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006310 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006311 !(handler->flags & HCI_MGMT_UNCONFIGURED)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006312 err = mgmt_cmd_status(sk, index, opcode,
6313 MGMT_STATUS_INVALID_INDEX);
Marcel Holtmann42a9bc142014-07-04 16:54:40 +02006314 goto done;
6315 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006316 }
6317
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006318 no_hdev = (handler->flags & HCI_MGMT_NO_HDEV);
6319 if (no_hdev != !hdev) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006320 err = mgmt_cmd_status(sk, index, opcode,
6321 MGMT_STATUS_INVALID_INDEX);
Marcel Holtmann73d1df22014-07-02 22:10:52 +02006322 goto done;
6323 }
6324
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006325 var_len = (handler->flags & HCI_MGMT_VAR_LEN);
6326 if ((var_len && len < handler->data_len) ||
6327 (!var_len && len != handler->data_len)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006328 err = mgmt_cmd_status(sk, index, opcode,
6329 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02006330 goto done;
6331 }
6332
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006333 if (hdev)
6334 mgmt_init_hdev(sk, hdev);
6335
6336 cp = buf + sizeof(*hdr);
6337
Johan Hedbergbe22b542012-03-01 22:24:41 +02006338 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02006339 if (err < 0)
6340 goto done;
6341
Johan Hedberg03811012010-12-08 00:21:06 +02006342 err = msglen;
6343
6344done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006345 if (hdev)
6346 hci_dev_put(hdev);
6347
Johan Hedberg03811012010-12-08 00:21:06 +02006348 kfree(buf);
6349 return err;
6350}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006351
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006352void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006353{
Marcel Holtmann1514b892013-10-06 08:25:01 -07006354 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006355 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006356
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006357 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6358 return;
6359
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006360 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006361 mgmt_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev, NULL, 0, NULL);
6362 else
6363 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006364}
6365
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006366void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006367{
Johan Hedberg5f159032012-03-02 03:13:19 +02006368 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006369
Marcel Holtmann1514b892013-10-06 08:25:01 -07006370 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006371 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006372
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006373 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6374 return;
6375
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02006376 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006377
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006378 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmannedd38962014-07-02 21:30:55 +02006379 mgmt_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0, NULL);
6380 else
6381 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006382}
6383
Andre Guedes6046dc32014-02-26 20:21:51 -03006384/* This function requires the caller holds hdev->lock */
Johan Hedberg2cf22212014-12-19 22:26:00 +02006385static void restart_le_actions(struct hci_request *req)
Andre Guedes6046dc32014-02-26 20:21:51 -03006386{
Johan Hedberg2cf22212014-12-19 22:26:00 +02006387 struct hci_dev *hdev = req->hdev;
Andre Guedes6046dc32014-02-26 20:21:51 -03006388 struct hci_conn_params *p;
6389
6390 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006391 /* Needed for AUTO_OFF case where might not "really"
6392 * have been powered off.
6393 */
6394 list_del_init(&p->action);
6395
6396 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006397 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006398 case HCI_AUTO_CONN_ALWAYS:
6399 list_add(&p->action, &hdev->pend_le_conns);
6400 break;
6401 case HCI_AUTO_CONN_REPORT:
6402 list_add(&p->action, &hdev->pend_le_reports);
6403 break;
6404 default:
6405 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006406 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006407 }
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006408
Johan Hedberg2cf22212014-12-19 22:26:00 +02006409 __hci_update_background_scan(req);
Andre Guedes6046dc32014-02-26 20:21:51 -03006410}
6411
Marcel Holtmann1904a852015-01-11 13:50:44 -08006412static void powered_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg229ab392013-03-15 17:06:53 -05006413{
6414 struct cmd_lookup match = { NULL, hdev };
6415
6416 BT_DBG("status 0x%02x", status);
6417
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006418 if (!status) {
6419 /* Register the available SMP channels (BR/EDR and LE) only
6420 * when successfully powering on the controller. This late
6421 * registration is required so that LE SMP can clearly
6422 * decide if the public address or static address is used.
6423 */
6424 smp_register(hdev);
6425 }
6426
Johan Hedberg229ab392013-03-15 17:06:53 -05006427 hci_dev_lock(hdev);
6428
6429 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6430
6431 new_settings(hdev, match.sk);
6432
6433 hci_dev_unlock(hdev);
6434
6435 if (match.sk)
6436 sock_put(match.sk);
6437}
6438
Johan Hedberg70da6242013-03-15 17:06:51 -05006439static int powered_update_hci(struct hci_dev *hdev)
6440{
Johan Hedberg890ea892013-03-15 17:06:52 -05006441 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05006442 u8 link_sec;
6443
Johan Hedberg890ea892013-03-15 17:06:52 -05006444 hci_req_init(&req, hdev);
6445
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006446 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED) &&
Johan Hedberg70da6242013-03-15 17:06:51 -05006447 !lmp_host_ssp_capable(hdev)) {
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006448 u8 mode = 0x01;
Johan Hedberg70da6242013-03-15 17:06:51 -05006449
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006450 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
Johan Hedberg70da6242013-03-15 17:06:51 -05006451
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006452 if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) {
6453 u8 support = 0x01;
6454
6455 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT,
6456 sizeof(support), &support);
6457 }
Johan Hedbergec6f99b2014-12-12 13:30:11 +02006458 }
6459
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006460 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
Johan Hedbergc73eee92013-04-19 18:35:21 +03006461 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05006462 struct hci_cp_write_le_host_supported cp;
6463
Marcel Holtmann32226e42014-07-24 20:04:16 +02006464 cp.le = 0x01;
6465 cp.simul = 0x00;
Johan Hedberg70da6242013-03-15 17:06:51 -05006466
6467 /* Check first if we already have the right
6468 * host state (host features set)
6469 */
6470 if (cp.le != lmp_host_le_capable(hdev) ||
6471 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05006472 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
6473 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05006474 }
6475
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07006476 if (lmp_le_capable(hdev)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006477 /* Make sure the controller has a good default for
6478 * advertising data. This also applies to the case
6479 * where BR/EDR was toggled during the AUTO_OFF phase.
6480 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006481 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07006482 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07006483 update_scan_rsp_data(&req);
6484 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006485
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006486 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07006487 enable_advertising(&req);
Johan Hedberg2cf22212014-12-19 22:26:00 +02006488
6489 restart_le_actions(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03006490 }
6491
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006492 link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg70da6242013-03-15 17:06:51 -05006493 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05006494 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
6495 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05006496
6497 if (lmp_bredr_capable(hdev)) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006498 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg406ef2a2015-03-10 20:14:27 +02006499 write_fast_connectable(&req, true);
6500 else
6501 write_fast_connectable(&req, false);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02006502 __hci_update_page_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006503 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05006504 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006505 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05006506 }
6507
Johan Hedberg229ab392013-03-15 17:06:53 -05006508 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05006509}
6510
Johan Hedberg744cf192011-11-08 20:40:14 +02006511int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006512{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006513 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006514 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006515 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006516
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006517 if (!hci_dev_test_flag(hdev, HCI_MGMT))
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006518 return 0;
6519
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006520 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05006521 if (powered_update_hci(hdev) == 0)
6522 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02006523
Johan Hedberg229ab392013-03-15 17:06:53 -05006524 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
6525 &match);
6526 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006527 }
6528
Johan Hedberg229ab392013-03-15 17:06:53 -05006529 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006530
6531 /* If the power off is because of hdev unregistration let
6532 * use the appropriate INVALID_INDEX status. Otherwise use
6533 * NOT_POWERED. We cover both scenarios here since later in
6534 * mgmt_index_removed() any hci_conn callbacks will have already
6535 * been triggered, potentially causing misleading DISCONNECTED
6536 * status responses.
6537 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006538 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006539 status = MGMT_STATUS_INVALID_INDEX;
6540 else
6541 status = MGMT_STATUS_NOT_POWERED;
6542
6543 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006544
6545 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
6546 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6547 zero_cod, sizeof(zero_cod), NULL);
6548
6549new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02006550 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006551
6552 if (match.sk)
6553 sock_put(match.sk);
6554
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006555 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006556}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006557
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006558void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006559{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006560 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006561 u8 status;
6562
6563 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
6564 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006565 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006566
6567 if (err == -ERFKILL)
6568 status = MGMT_STATUS_RFKILLED;
6569 else
6570 status = MGMT_STATUS_FAILED;
6571
Johan Hedberga69e8372015-03-06 21:08:53 +02006572 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006573
6574 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006575}
6576
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006577void mgmt_discoverable_timeout(struct hci_dev *hdev)
6578{
6579 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006580
6581 hci_dev_lock(hdev);
6582
6583 /* When discoverable timeout triggers, then just make sure
6584 * the limited discoverable flag is cleared. Even in the case
6585 * of a timeout triggered from general discoverable, it is
6586 * safe to unconditionally clear the flag.
6587 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006588 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
6589 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006590
6591 hci_req_init(&req, hdev);
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006592 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg4b580612013-10-19 23:38:21 +03006593 u8 scan = SCAN_PAGE;
6594 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
6595 sizeof(scan), &scan);
6596 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006597 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03006598 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006599 hci_req_run(&req, NULL);
6600
6601 hdev->discov_timeout = 0;
6602
Johan Hedberg9a43e252013-10-20 19:00:07 +03006603 new_settings(hdev, NULL);
6604
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006605 hci_dev_unlock(hdev);
6606}
6607
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006608void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
6609 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006610{
Johan Hedberg86742e12011-11-07 23:13:38 +02006611 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006612
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006613 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006614
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006615 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02006616 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006617 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006618 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03006619 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006620 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006621
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006622 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006623}
Johan Hedbergf7520542011-01-20 12:34:39 +02006624
Johan Hedbergd7b25452014-05-23 13:19:53 +03006625static u8 mgmt_ltk_type(struct smp_ltk *ltk)
6626{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006627 switch (ltk->type) {
6628 case SMP_LTK:
6629 case SMP_LTK_SLAVE:
6630 if (ltk->authenticated)
6631 return MGMT_LTK_AUTHENTICATED;
6632 return MGMT_LTK_UNAUTHENTICATED;
6633 case SMP_LTK_P256:
6634 if (ltk->authenticated)
6635 return MGMT_LTK_P256_AUTH;
6636 return MGMT_LTK_P256_UNAUTH;
6637 case SMP_LTK_P256_DEBUG:
6638 return MGMT_LTK_P256_DEBUG;
6639 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006640
6641 return MGMT_LTK_UNAUTHENTICATED;
6642}
6643
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006644void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006645{
6646 struct mgmt_ev_new_long_term_key ev;
6647
6648 memset(&ev, 0, sizeof(ev));
6649
Marcel Holtmann5192d302014-02-19 17:11:58 -08006650 /* Devices using resolvable or non-resolvable random addresses
6651 * without providing an indentity resolving key don't require
6652 * to store long term keys. Their addresses will change the
6653 * next time around.
6654 *
6655 * Only when a remote device provides an identity address
6656 * make sure the long term key is stored. If the remote
6657 * identity is known, the long term keys are internally
6658 * mapped to the identity address. So allow static random
6659 * and public addresses here.
6660 */
Johan Hedbergba74b662014-02-19 14:57:45 +02006661 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6662 (key->bdaddr.b[5] & 0xc0) != 0xc0)
6663 ev.store_hint = 0x00;
6664 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006665 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02006666
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006667 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006668 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03006669 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006670 ev.key.enc_size = key->enc_size;
6671 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08006672 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006673
Johan Hedberg2ceba532014-06-16 19:25:16 +03006674 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006675 ev.key.master = 1;
6676
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006677 memcpy(ev.key.val, key->val, sizeof(key->val));
6678
Marcel Holtmann083368f2013-10-15 14:26:29 -07006679 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006680}
6681
Johan Hedberg95fbac82014-02-19 15:18:31 +02006682void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk)
6683{
6684 struct mgmt_ev_new_irk ev;
6685
6686 memset(&ev, 0, sizeof(ev));
6687
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08006688 /* For identity resolving keys from devices that are already
6689 * using a public address or static random address, do not
6690 * ask for storing this key. The identity resolving key really
6691 * is only mandatory for devices using resovlable random
6692 * addresses.
6693 *
6694 * Storing all identity resolving keys has the downside that
6695 * they will be also loaded on next boot of they system. More
6696 * identity resolving keys, means more time during scanning is
6697 * needed to actually resolve these addresses.
6698 */
6699 if (bacmp(&irk->rpa, BDADDR_ANY))
6700 ev.store_hint = 0x01;
6701 else
6702 ev.store_hint = 0x00;
6703
Johan Hedberg95fbac82014-02-19 15:18:31 +02006704 bacpy(&ev.rpa, &irk->rpa);
6705 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
6706 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
6707 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
6708
6709 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
6710}
6711
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006712void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
6713 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006714{
6715 struct mgmt_ev_new_csrk ev;
6716
6717 memset(&ev, 0, sizeof(ev));
6718
6719 /* Devices using resolvable or non-resolvable random addresses
6720 * without providing an indentity resolving key don't require
6721 * to store signature resolving keys. Their addresses will change
6722 * the next time around.
6723 *
6724 * Only when a remote device provides an identity address
6725 * make sure the signature resolving key is stored. So allow
6726 * static random and public addresses here.
6727 */
6728 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6729 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
6730 ev.store_hint = 0x00;
6731 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006732 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006733
6734 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
6735 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02006736 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006737 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
6738
6739 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
6740}
6741
Andre Guedesffb5a8272014-07-01 18:10:11 -03006742void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03006743 u8 bdaddr_type, u8 store_hint, u16 min_interval,
6744 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03006745{
6746 struct mgmt_ev_new_conn_param ev;
6747
Johan Hedbergc103aea2014-07-02 17:37:34 +03006748 if (!hci_is_identity_address(bdaddr, bdaddr_type))
6749 return;
6750
Andre Guedesffb5a8272014-07-01 18:10:11 -03006751 memset(&ev, 0, sizeof(ev));
6752 bacpy(&ev.addr.bdaddr, bdaddr);
6753 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03006754 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03006755 ev.min_interval = cpu_to_le16(min_interval);
6756 ev.max_interval = cpu_to_le16(max_interval);
6757 ev.latency = cpu_to_le16(latency);
6758 ev.timeout = cpu_to_le16(timeout);
6759
6760 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
6761}
6762
Marcel Holtmann94933992013-10-15 10:26:39 -07006763static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
6764 u8 data_len)
6765{
6766 eir[eir_len++] = sizeof(type) + data_len;
6767 eir[eir_len++] = type;
6768 memcpy(&eir[eir_len], data, data_len);
6769 eir_len += data_len;
6770
6771 return eir_len;
6772}
6773
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006774void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
6775 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02006776{
Johan Hedbergb644ba32012-01-17 21:48:47 +02006777 char buf[512];
6778 struct mgmt_ev_device_connected *ev = (void *) buf;
6779 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02006780
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006781 bacpy(&ev->addr.bdaddr, &conn->dst);
6782 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02006783
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02006784 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02006785
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006786 /* We must ensure that the EIR Data fields are ordered and
6787 * unique. Keep it simple for now and avoid the problem by not
6788 * adding any BR/EDR data to the LE adv.
6789 */
6790 if (conn->le_adv_data_len > 0) {
6791 memcpy(&ev->eir[eir_len],
6792 conn->le_adv_data, conn->le_adv_data_len);
6793 eir_len = conn->le_adv_data_len;
6794 } else {
6795 if (name_len > 0)
6796 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
6797 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006798
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00006799 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006800 eir_len = eir_append_data(ev->eir, eir_len,
6801 EIR_CLASS_OF_DEV,
6802 conn->dev_class, 3);
6803 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02006804
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02006805 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006806
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07006807 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
6808 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02006809}
6810
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006811static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006812{
Johan Hedberg8962ee72011-01-20 12:40:27 +02006813 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006814
Johan Hedbergf5818c22014-12-05 13:36:02 +02006815 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006816
6817 *sk = cmd->sk;
6818 sock_hold(*sk);
6819
Johan Hedberga664b5b2011-02-19 12:06:02 -03006820 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006821}
6822
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006823static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02006824{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006825 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02006826 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02006827
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006828 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
6829
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02006830 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02006831 mgmt_pending_remove(cmd);
6832}
6833
Johan Hedberg84c61d92014-08-01 11:13:30 +03006834bool mgmt_powering_down(struct hci_dev *hdev)
6835{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006836 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03006837 struct mgmt_mode *cp;
6838
6839 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
6840 if (!cmd)
6841 return false;
6842
6843 cp = cmd->param;
6844 if (!cp->val)
6845 return true;
6846
6847 return false;
6848}
6849
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006850void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006851 u8 link_type, u8 addr_type, u8 reason,
6852 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02006853{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006854 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006855 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006856
Johan Hedberg84c61d92014-08-01 11:13:30 +03006857 /* The connection is still in hci_conn_hash so test for 1
6858 * instead of 0 to know if this is the last one.
6859 */
6860 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6861 cancel_delayed_work(&hdev->power_off);
6862 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02006863 }
6864
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006865 if (!mgmt_connected)
6866 return;
6867
Andre Guedes57eb7762013-10-30 19:01:41 -03006868 if (link_type != ACL_LINK && link_type != LE_LINK)
6869 return;
6870
Johan Hedberg744cf192011-11-08 20:40:14 +02006871 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02006872
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006873 bacpy(&ev.addr.bdaddr, bdaddr);
6874 ev.addr.type = link_to_bdaddr(link_type, addr_type);
6875 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02006876
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006877 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006878
6879 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01006880 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006881
Johan Hedberg124f6e32012-02-09 13:50:12 +02006882 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006883 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006884}
6885
Marcel Holtmann78929242013-10-06 23:55:47 -07006886void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
6887 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006888{
Andre Guedes3655bba2013-10-30 19:01:40 -03006889 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
6890 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006891 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006892
Jefferson Delfes36a75f12012-09-18 13:36:54 -04006893 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
6894 hdev);
6895
Johan Hedberg2e58ef32011-11-08 20:40:15 +02006896 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006897 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07006898 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006899
Andre Guedes3655bba2013-10-30 19:01:40 -03006900 cp = cmd->param;
6901
6902 if (bacmp(bdaddr, &cp->addr.bdaddr))
6903 return;
6904
6905 if (cp->addr.type != bdaddr_type)
6906 return;
6907
Johan Hedbergf5818c22014-12-05 13:36:02 +02006908 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006909 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02006910}
Johan Hedberg17d5c042011-01-22 06:09:08 +02006911
Marcel Holtmann445608d2013-10-06 23:55:48 -07006912void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
6913 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02006914{
6915 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02006916
Johan Hedberg84c61d92014-08-01 11:13:30 +03006917 /* The connection is still in hci_conn_hash so test for 1
6918 * instead of 0 to know if this is the last one.
6919 */
6920 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6921 cancel_delayed_work(&hdev->power_off);
6922 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02006923 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02006924
Johan Hedberg4c659c32011-11-07 23:13:39 +02006925 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006926 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02006927 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006928
Marcel Holtmann445608d2013-10-06 23:55:48 -07006929 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02006930}
Johan Hedberg980e1a52011-01-22 06:10:07 +02006931
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006932void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006933{
6934 struct mgmt_ev_pin_code_request ev;
6935
Johan Hedbergd8457692012-02-17 14:24:57 +02006936 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006937 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02006938 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006939
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07006940 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006941}
6942
Marcel Holtmanne669cf82013-10-15 14:26:21 -07006943void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
6944 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006945{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006946 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006947
Johan Hedberg2e58ef32011-11-08 20:40:15 +02006948 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006949 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07006950 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006951
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006952 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006953 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006954}
6955
Marcel Holtmann3eb38522013-10-15 14:26:22 -07006956void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
6957 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02006958{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006959 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006960
Johan Hedberg2e58ef32011-11-08 20:40:15 +02006961 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006962 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07006963 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02006964
Johan Hedberg7776d1d2014-12-05 13:36:03 +02006965 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03006966 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02006967}
Johan Hedberga5c29682011-02-19 12:05:57 -03006968
Johan Hedberg744cf192011-11-08 20:40:14 +02006969int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02006970 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006971 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03006972{
6973 struct mgmt_ev_user_confirm_request ev;
6974
Johan Hedberg744cf192011-11-08 20:40:14 +02006975 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03006976
Johan Hedberg272d90d2012-02-09 15:26:12 +02006977 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006978 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07006979 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02006980 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03006981
Johan Hedberg744cf192011-11-08 20:40:14 +02006982 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006983 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03006984}
6985
Johan Hedberg272d90d2012-02-09 15:26:12 +02006986int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03006987 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08006988{
6989 struct mgmt_ev_user_passkey_request ev;
6990
6991 BT_DBG("%s", hdev->name);
6992
Johan Hedberg272d90d2012-02-09 15:26:12 +02006993 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006994 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08006995
6996 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03006997 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08006998}
6999
Brian Gix0df4c182011-11-16 13:53:13 -08007000static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007001 u8 link_type, u8 addr_type, u8 status,
7002 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007003{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007004 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007005
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007006 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007007 if (!cmd)
7008 return -ENOENT;
7009
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007010 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007011 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007012
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007013 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007014}
7015
Johan Hedberg744cf192011-11-08 20:40:14 +02007016int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007017 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007018{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007019 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007020 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007021}
7022
Johan Hedberg272d90d2012-02-09 15:26:12 +02007023int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007024 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007025{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007026 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007027 status,
7028 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007029}
Johan Hedberg2a611692011-02-19 12:06:00 -03007030
Brian Gix604086b2011-11-23 08:28:33 -08007031int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007032 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007033{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007034 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007035 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007036}
7037
Johan Hedberg272d90d2012-02-09 15:26:12 +02007038int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007039 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007040{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007041 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007042 status,
7043 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007044}
7045
Johan Hedberg92a25252012-09-06 18:39:26 +03007046int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7047 u8 link_type, u8 addr_type, u32 passkey,
7048 u8 entered)
7049{
7050 struct mgmt_ev_passkey_notify ev;
7051
7052 BT_DBG("%s", hdev->name);
7053
7054 bacpy(&ev.addr.bdaddr, bdaddr);
7055 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7056 ev.passkey = __cpu_to_le32(passkey);
7057 ev.entered = entered;
7058
7059 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7060}
7061
Johan Hedberge1e930f2014-09-08 17:09:49 -07007062void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007063{
7064 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007065 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007066 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007067
Johan Hedberge1e930f2014-09-08 17:09:49 -07007068 bacpy(&ev.addr.bdaddr, &conn->dst);
7069 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7070 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007071
Johan Hedberge1e930f2014-09-08 17:09:49 -07007072 cmd = find_pairing(conn);
7073
7074 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7075 cmd ? cmd->sk : NULL);
7076
Johan Hedberga511b352014-12-11 21:45:45 +02007077 if (cmd) {
7078 cmd->cmd_complete(cmd, status);
7079 mgmt_pending_remove(cmd);
7080 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007081}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007082
Marcel Holtmann464996a2013-10-15 14:26:24 -07007083void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007084{
7085 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007086 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007087
7088 if (status) {
7089 u8 mgmt_err = mgmt_status(status);
7090 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007091 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007092 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007093 }
7094
Marcel Holtmann464996a2013-10-15 14:26:24 -07007095 if (test_bit(HCI_AUTH, &hdev->flags))
7096 changed = !test_and_set_bit(HCI_LINK_SECURITY,
7097 &hdev->dev_flags);
7098 else
7099 changed = test_and_clear_bit(HCI_LINK_SECURITY,
7100 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007101
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007102 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007103 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007104
Johan Hedberg47990ea2012-02-22 11:58:37 +02007105 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007106 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007107
7108 if (match.sk)
7109 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007110}
7111
Johan Hedberg890ea892013-03-15 17:06:52 -05007112static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007113{
Johan Hedberg890ea892013-03-15 17:06:52 -05007114 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007115 struct hci_cp_write_eir cp;
7116
Johan Hedberg976eb202012-10-24 21:12:01 +03007117 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007118 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007119
Johan Hedbergc80da272012-02-22 15:38:48 +02007120 memset(hdev->eir, 0, sizeof(hdev->eir));
7121
Johan Hedbergcacaf522012-02-21 00:52:42 +02007122 memset(&cp, 0, sizeof(cp));
7123
Johan Hedberg890ea892013-03-15 17:06:52 -05007124 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007125}
7126
Marcel Holtmann3e248562013-10-15 14:26:25 -07007127void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007128{
7129 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007130 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007131 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007132
7133 if (status) {
7134 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007135
7136 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007137 &hdev->dev_flags)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007138 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007139 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007140 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007141
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007142 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7143 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007144 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007145 }
7146
7147 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007148 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007149 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007150 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
7151 if (!changed)
7152 changed = test_and_clear_bit(HCI_HS_ENABLED,
7153 &hdev->dev_flags);
7154 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007155 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007156 }
7157
7158 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7159
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007160 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007161 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007162
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007163 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007164 sock_put(match.sk);
7165
Johan Hedberg890ea892013-03-15 17:06:52 -05007166 hci_req_init(&req, hdev);
7167
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007168 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7169 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007170 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7171 sizeof(enable), &enable);
Johan Hedberg890ea892013-03-15 17:06:52 -05007172 update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007173 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007174 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007175 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007176
7177 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007178}
7179
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007180static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007181{
7182 struct cmd_lookup *match = data;
7183
Johan Hedberg90e70452012-02-23 23:09:40 +02007184 if (match->sk == NULL) {
7185 match->sk = cmd->sk;
7186 sock_hold(match->sk);
7187 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007188}
7189
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007190void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7191 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007192{
Johan Hedberg90e70452012-02-23 23:09:40 +02007193 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007194
Johan Hedberg92da6092013-03-15 17:06:55 -05007195 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7196 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7197 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007198
7199 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007200 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
7201 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02007202
7203 if (match.sk)
7204 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007205}
7206
Marcel Holtmann7667da32013-10-15 14:26:27 -07007207void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007208{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007209 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007210 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007211
Johan Hedberg13928972013-03-15 17:07:00 -05007212 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007213 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007214
7215 memset(&ev, 0, sizeof(ev));
7216 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007217 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007218
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007219 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007220 if (!cmd) {
7221 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007222
Johan Hedberg13928972013-03-15 17:07:00 -05007223 /* If this is a HCI command related to powering on the
7224 * HCI dev don't send any mgmt signals.
7225 */
7226 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007227 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007228 }
7229
Marcel Holtmann7667da32013-10-15 14:26:27 -07007230 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7231 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007232}
Szymon Jancc35938b2011-03-22 13:12:21 +01007233
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007234void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
Johan Hedberg38da1702014-11-17 20:52:20 +02007235 u8 *rand192, u8 *hash256, u8 *rand256,
7236 u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01007237{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007238 struct mgmt_pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01007239
Johan Hedberg744cf192011-11-08 20:40:14 +02007240 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01007241
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007242 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01007243 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07007244 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01007245
7246 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02007247 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
7248 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01007249 } else {
Johan Hedberg66f096f2015-02-02 13:23:42 +02007250 struct mgmt_rp_read_local_oob_data rp;
7251 size_t rp_size = sizeof(rp);
7252
7253 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
7254 memcpy(rp.rand192, rand192, sizeof(rp.rand192));
7255
Johan Hedberg710f11c2014-05-26 11:21:22 +03007256 if (bredr_sc_enabled(hdev) && hash256 && rand256) {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007257 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
Johan Hedberg38da1702014-11-17 20:52:20 +02007258 memcpy(rp.rand256, rand256, sizeof(rp.rand256));
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007259 } else {
Johan Hedberg66f096f2015-02-02 13:23:42 +02007260 rp_size -= sizeof(rp.hash256) + sizeof(rp.rand256);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007261 }
Johan Hedberg66f096f2015-02-02 13:23:42 +02007262
Johan Hedberg2a1afb52015-03-06 21:08:54 +02007263 mgmt_cmd_complete(cmd->sk, hdev->id,
7264 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
7265 &rp, rp_size);
Szymon Jancc35938b2011-03-22 13:12:21 +01007266 }
7267
7268 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01007269}
Johan Hedberge17acd42011-03-30 23:57:16 +03007270
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007271static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7272{
7273 int i;
7274
7275 for (i = 0; i < uuid_count; i++) {
7276 if (!memcmp(uuid, uuids[i], 16))
7277 return true;
7278 }
7279
7280 return false;
7281}
7282
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007283static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7284{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007285 u16 parsed = 0;
7286
7287 while (parsed < eir_len) {
7288 u8 field_len = eir[0];
7289 u8 uuid[16];
7290 int i;
7291
7292 if (field_len == 0)
7293 break;
7294
7295 if (eir_len - parsed < field_len + 1)
7296 break;
7297
7298 switch (eir[1]) {
7299 case EIR_UUID16_ALL:
7300 case EIR_UUID16_SOME:
7301 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007302 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007303 uuid[13] = eir[i + 3];
7304 uuid[12] = eir[i + 2];
7305 if (has_uuid(uuid, uuid_count, uuids))
7306 return true;
7307 }
7308 break;
7309 case EIR_UUID32_ALL:
7310 case EIR_UUID32_SOME:
7311 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007312 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007313 uuid[15] = eir[i + 5];
7314 uuid[14] = eir[i + 4];
7315 uuid[13] = eir[i + 3];
7316 uuid[12] = eir[i + 2];
7317 if (has_uuid(uuid, uuid_count, uuids))
7318 return true;
7319 }
7320 break;
7321 case EIR_UUID128_ALL:
7322 case EIR_UUID128_SOME:
7323 for (i = 0; i + 17 <= field_len; i += 16) {
7324 memcpy(uuid, eir + i + 2, 16);
7325 if (has_uuid(uuid, uuid_count, uuids))
7326 return true;
7327 }
7328 break;
7329 }
7330
7331 parsed += field_len + 1;
7332 eir += field_len + 1;
7333 }
7334
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007335 return false;
7336}
7337
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007338static void restart_le_scan(struct hci_dev *hdev)
7339{
7340 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007341 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007342 return;
7343
7344 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7345 hdev->discovery.scan_start +
7346 hdev->discovery.scan_duration))
7347 return;
7348
7349 queue_delayed_work(hdev->workqueue, &hdev->le_scan_restart,
7350 DISCOV_LE_RESTART_DELAY);
7351}
7352
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007353static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7354 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7355{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007356 /* If a RSSI threshold has been specified, and
7357 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7358 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7359 * is set, let it through for further processing, as we might need to
7360 * restart the scan.
7361 *
7362 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7363 * the results are also dropped.
7364 */
7365 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7366 (rssi == HCI_RSSI_INVALID ||
7367 (rssi < hdev->discovery.rssi &&
7368 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7369 return false;
7370
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007371 if (hdev->discovery.uuid_count != 0) {
7372 /* If a list of UUIDs is provided in filter, results with no
7373 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007374 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007375 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7376 hdev->discovery.uuids) &&
7377 !eir_has_uuids(scan_rsp, scan_rsp_len,
7378 hdev->discovery.uuid_count,
7379 hdev->discovery.uuids))
7380 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007381 }
7382
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007383 /* If duplicate filtering does not report RSSI changes, then restart
7384 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007385 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007386 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7387 restart_le_scan(hdev);
7388
7389 /* Validate RSSI value against the RSSI threshold once more. */
7390 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7391 rssi < hdev->discovery.rssi)
7392 return false;
7393 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007394
7395 return true;
7396}
7397
Marcel Holtmann901801b2013-10-06 23:55:51 -07007398void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007399 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7400 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007401{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007402 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007403 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007404 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007405
Johan Hedberg75ce2082014-07-02 22:42:01 +03007406 /* Don't send events for a non-kernel initiated discovery. With
7407 * LE one exception is if we have pend_le_reports > 0 in which
7408 * case we're doing passive scanning and want these events.
7409 */
7410 if (!hci_discovery_active(hdev)) {
7411 if (link_type == ACL_LINK)
7412 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007413 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007414 return;
7415 }
Andre Guedes12602d02013-04-30 15:29:40 -03007416
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007417 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007418 /* We are using service discovery */
7419 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7420 scan_rsp_len))
7421 return;
7422 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007423
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007424 /* Make sure that the buffer is big enough. The 5 extra bytes
7425 * are for the potential CoD field.
7426 */
7427 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007428 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007429
Johan Hedberg1dc06092012-01-15 21:01:23 +02007430 memset(buf, 0, sizeof(buf));
7431
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007432 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7433 * RSSI value was reported as 0 when not available. This behavior
7434 * is kept when using device discovery. This is required for full
7435 * backwards compatibility with the API.
7436 *
7437 * However when using service discovery, the value 127 will be
7438 * returned when the RSSI is not available.
7439 */
Szymon Janc91200e92015-01-22 16:57:05 +01007440 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7441 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007442 rssi = 0;
7443
Johan Hedberg841c5642014-07-07 12:45:54 +03007444 bacpy(&ev->addr.bdaddr, bdaddr);
7445 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007446 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007447 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007448
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007449 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007450 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007451 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007452
Johan Hedberg1dc06092012-01-15 21:01:23 +02007453 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
7454 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007455 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007456
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007457 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007458 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007459 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007460
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007461 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7462 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007463
Marcel Holtmann901801b2013-10-06 23:55:51 -07007464 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007465}
Johan Hedberga88a9652011-03-30 13:18:12 +03007466
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007467void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7468 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007469{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007470 struct mgmt_ev_device_found *ev;
7471 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7472 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007473
Johan Hedbergb644ba32012-01-17 21:48:47 +02007474 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007475
Johan Hedbergb644ba32012-01-17 21:48:47 +02007476 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007477
Johan Hedbergb644ba32012-01-17 21:48:47 +02007478 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007479 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007480 ev->rssi = rssi;
7481
7482 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007483 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007484
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007485 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007486
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007487 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007488}
Johan Hedberg314b2382011-04-27 10:29:57 -04007489
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007490void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007491{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007492 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007493
Andre Guedes343fb142011-11-22 17:14:19 -03007494 BT_DBG("%s discovering %u", hdev->name, discovering);
7495
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007496 memset(&ev, 0, sizeof(ev));
7497 ev.type = hdev->discovery.type;
7498 ev.discovering = discovering;
7499
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007500 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007501}
Antti Julku5e762442011-08-25 16:48:02 +03007502
Marcel Holtmann1904a852015-01-11 13:50:44 -08007503static void adv_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Marcel Holtmann5976e602013-10-06 04:08:14 -07007504{
7505 BT_DBG("%s status %u", hdev->name, status);
Marcel Holtmann5976e602013-10-06 04:08:14 -07007506}
7507
7508void mgmt_reenable_advertising(struct hci_dev *hdev)
7509{
7510 struct hci_request req;
7511
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007512 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Marcel Holtmann5976e602013-10-06 04:08:14 -07007513 return;
7514
7515 hci_req_init(&req, hdev);
7516 enable_advertising(&req);
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03007517 hci_req_run(&req, adv_enable_complete);
Marcel Holtmann5976e602013-10-06 04:08:14 -07007518}
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007519
7520static struct hci_mgmt_chan chan = {
7521 .channel = HCI_CHANNEL_CONTROL,
7522 .handler_count = ARRAY_SIZE(mgmt_handlers),
7523 .handlers = mgmt_handlers,
7524};
7525
7526int mgmt_init(void)
7527{
7528 return hci_mgmt_chan_register(&chan);
7529}
7530
7531void mgmt_exit(void)
7532{
7533 hci_mgmt_chan_unregister(&chan);
7534}