blob: 920acf0625f6fe899b56044d3d37662d9d7f00e4 [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,
Marcel Holtmann96f14742015-03-14 19:27:57 -070099 MGMT_OP_READ_EXT_INDEX_LIST,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200100};
101
102static const u16 mgmt_events[] = {
103 MGMT_EV_CONTROLLER_ERROR,
104 MGMT_EV_INDEX_ADDED,
105 MGMT_EV_INDEX_REMOVED,
106 MGMT_EV_NEW_SETTINGS,
107 MGMT_EV_CLASS_OF_DEV_CHANGED,
108 MGMT_EV_LOCAL_NAME_CHANGED,
109 MGMT_EV_NEW_LINK_KEY,
110 MGMT_EV_NEW_LONG_TERM_KEY,
111 MGMT_EV_DEVICE_CONNECTED,
112 MGMT_EV_DEVICE_DISCONNECTED,
113 MGMT_EV_CONNECT_FAILED,
114 MGMT_EV_PIN_CODE_REQUEST,
115 MGMT_EV_USER_CONFIRM_REQUEST,
116 MGMT_EV_USER_PASSKEY_REQUEST,
117 MGMT_EV_AUTH_FAILED,
118 MGMT_EV_DEVICE_FOUND,
119 MGMT_EV_DISCOVERING,
120 MGMT_EV_DEVICE_BLOCKED,
121 MGMT_EV_DEVICE_UNBLOCKED,
122 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300123 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800124 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700125 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200126 MGMT_EV_DEVICE_ADDED,
127 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300128 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200129 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd38962014-07-02 21:30:55 +0200130 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200131 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700132 MGMT_EV_EXT_INDEX_ADDED,
133 MGMT_EV_EXT_INDEX_REMOVED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200134};
135
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800136#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200137
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200138#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
139 "\x00\x00\x00\x00\x00\x00\x00\x00"
140
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200141struct mgmt_pending_cmd {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200142 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200143 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200144 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100145 void *param;
Johan Hedberg323b0b82014-12-05 13:36:01 +0200146 size_t param_len;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200147 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300148 void *user_data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200149 int (*cmd_complete)(struct mgmt_pending_cmd *cmd, u8 status);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200150};
151
Johan Hedbergca69b792011-11-11 18:10:00 +0200152/* HCI to MGMT error code conversion table */
153static u8 mgmt_status_table[] = {
154 MGMT_STATUS_SUCCESS,
155 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
156 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
157 MGMT_STATUS_FAILED, /* Hardware Failure */
158 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
159 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200160 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200161 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
162 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
163 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
164 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
165 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
166 MGMT_STATUS_BUSY, /* Command Disallowed */
167 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
168 MGMT_STATUS_REJECTED, /* Rejected Security */
169 MGMT_STATUS_REJECTED, /* Rejected Personal */
170 MGMT_STATUS_TIMEOUT, /* Host Timeout */
171 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
172 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
173 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
174 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
175 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
176 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
177 MGMT_STATUS_BUSY, /* Repeated Attempts */
178 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
179 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
180 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
181 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
182 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
183 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
184 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
185 MGMT_STATUS_FAILED, /* Unspecified Error */
186 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
187 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
188 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
189 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
190 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
191 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
192 MGMT_STATUS_FAILED, /* Unit Link Key Used */
193 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
194 MGMT_STATUS_TIMEOUT, /* Instant Passed */
195 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
196 MGMT_STATUS_FAILED, /* Transaction Collision */
197 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
198 MGMT_STATUS_REJECTED, /* QoS Rejected */
199 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
200 MGMT_STATUS_REJECTED, /* Insufficient Security */
201 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
202 MGMT_STATUS_BUSY, /* Role Switch Pending */
203 MGMT_STATUS_FAILED, /* Slot Violation */
204 MGMT_STATUS_FAILED, /* Role Switch Failed */
205 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
206 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
207 MGMT_STATUS_BUSY, /* Host Busy Pairing */
208 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
209 MGMT_STATUS_BUSY, /* Controller Busy */
210 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
211 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
212 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
213 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
214 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
215};
216
217static u8 mgmt_status(u8 hci_status)
218{
219 if (hci_status < ARRAY_SIZE(mgmt_status_table))
220 return mgmt_status_table[hci_status];
221
222 return MGMT_STATUS_FAILED;
223}
224
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200225static int mgmt_send_event(u16 event, struct hci_dev *hdev,
226 unsigned short channel, void *data, u16 data_len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700227 int flag, struct sock *skip_sk)
Marcel Holtmann04c60f02014-07-04 19:06:22 +0200228{
229 struct sk_buff *skb;
230 struct mgmt_hdr *hdr;
231
232 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
233 if (!skb)
234 return -ENOMEM;
235
236 hdr = (void *) skb_put(skb, sizeof(*hdr));
237 hdr->opcode = cpu_to_le16(event);
238 if (hdev)
239 hdr->index = cpu_to_le16(hdev->id);
240 else
241 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
242 hdr->len = cpu_to_le16(data_len);
243
244 if (data)
245 memcpy(skb_put(skb, data_len), data, data_len);
246
247 /* Time stamp */
248 __net_timestamp(skb);
249
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700250 hci_send_to_channel(channel, skb, flag, skip_sk);
Marcel Holtmann04c60f02014-07-04 19:06:22 +0200251 kfree_skb(skb);
252
253 return 0;
254}
255
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700256static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
257 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700258{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700259 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
260 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700261}
262
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200263static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
264 struct sock *skip_sk)
265{
266 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700267 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200268}
269
Johan Hedberga69e8372015-03-06 21:08:53 +0200270static int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200271{
272 struct sk_buff *skb;
273 struct mgmt_hdr *hdr;
274 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300275 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200276
Szymon Janc34eb5252011-02-28 14:10:08 +0100277 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200278
Andre Guedes790eff42012-06-07 19:05:46 -0300279 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200280 if (!skb)
281 return -ENOMEM;
282
283 hdr = (void *) skb_put(skb, sizeof(*hdr));
284
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700285 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100286 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200287 hdr->len = cpu_to_le16(sizeof(*ev));
288
289 ev = (void *) skb_put(skb, sizeof(*ev));
290 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200291 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200292
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300293 err = sock_queue_rcv_skb(sk, skb);
294 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200295 kfree_skb(skb);
296
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300297 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200298}
299
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200300static int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
301 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200302{
303 struct sk_buff *skb;
304 struct mgmt_hdr *hdr;
305 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300306 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200307
308 BT_DBG("sock %p", sk);
309
Andre Guedes790eff42012-06-07 19:05:46 -0300310 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200311 if (!skb)
312 return -ENOMEM;
313
314 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200315
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700316 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100317 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200318 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200319
Johan Hedberga38528f2011-01-22 06:46:43 +0200320 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200321 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200322 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100323
324 if (rp)
325 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200326
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300327 err = sock_queue_rcv_skb(sk, skb);
328 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200329 kfree_skb(skb);
330
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100331 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200332}
333
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300334static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
335 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200336{
337 struct mgmt_rp_read_version rp;
338
339 BT_DBG("sock %p", sk);
340
341 rp.version = MGMT_VERSION;
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700342 rp.revision = cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200343
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200344 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
345 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200346}
347
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300348static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
349 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200350{
351 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200352 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
353 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200354 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200355 size_t rp_size;
356 int i, err;
357
358 BT_DBG("sock %p", sk);
359
360 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
361
362 rp = kmalloc(rp_size, GFP_KERNEL);
363 if (!rp)
364 return -ENOMEM;
365
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700366 rp->num_commands = cpu_to_le16(num_commands);
367 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200368
369 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
370 put_unaligned_le16(mgmt_commands[i], opcode);
371
372 for (i = 0; i < num_events; i++, opcode++)
373 put_unaligned_le16(mgmt_events[i], opcode);
374
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200375 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
376 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200377 kfree(rp);
378
379 return err;
380}
381
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300382static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
383 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200384{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200385 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200386 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200387 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200388 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300389 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200390
391 BT_DBG("sock %p", sk);
392
393 read_lock(&hci_dev_list_lock);
394
395 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300396 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200397 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700398 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700399 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200400 }
401
Johan Hedberga38528f2011-01-22 06:46:43 +0200402 rp_len = sizeof(*rp) + (2 * count);
403 rp = kmalloc(rp_len, GFP_ATOMIC);
404 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100405 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200406 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100407 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200408
Johan Hedberg476e44c2012-10-19 20:10:46 +0300409 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200410 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700411 if (hci_dev_test_flag(d, HCI_SETUP) ||
412 hci_dev_test_flag(d, HCI_CONFIG) ||
413 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200414 continue;
415
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200416 /* Devices marked as raw-only are neither configured
417 * nor unconfigured controllers.
418 */
419 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700420 continue;
421
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200422 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700423 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700424 rp->index[count++] = cpu_to_le16(d->id);
425 BT_DBG("Added hci%u", d->id);
426 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200427 }
428
Johan Hedberg476e44c2012-10-19 20:10:46 +0300429 rp->num_controllers = cpu_to_le16(count);
430 rp_len = sizeof(*rp) + (2 * count);
431
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200432 read_unlock(&hci_dev_list_lock);
433
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200434 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
435 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200436
Johan Hedberga38528f2011-01-22 06:46:43 +0200437 kfree(rp);
438
439 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200440}
441
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200442static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
443 void *data, u16 data_len)
444{
445 struct mgmt_rp_read_unconf_index_list *rp;
446 struct hci_dev *d;
447 size_t rp_len;
448 u16 count;
449 int err;
450
451 BT_DBG("sock %p", sk);
452
453 read_lock(&hci_dev_list_lock);
454
455 count = 0;
456 list_for_each_entry(d, &hci_dev_list, list) {
457 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700458 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200459 count++;
460 }
461
462 rp_len = sizeof(*rp) + (2 * count);
463 rp = kmalloc(rp_len, GFP_ATOMIC);
464 if (!rp) {
465 read_unlock(&hci_dev_list_lock);
466 return -ENOMEM;
467 }
468
469 count = 0;
470 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700471 if (hci_dev_test_flag(d, HCI_SETUP) ||
472 hci_dev_test_flag(d, HCI_CONFIG) ||
473 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200474 continue;
475
476 /* Devices marked as raw-only are neither configured
477 * nor unconfigured controllers.
478 */
479 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
480 continue;
481
482 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700483 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200484 rp->index[count++] = cpu_to_le16(d->id);
485 BT_DBG("Added hci%u", d->id);
486 }
487 }
488
489 rp->num_controllers = cpu_to_le16(count);
490 rp_len = sizeof(*rp) + (2 * count);
491
492 read_unlock(&hci_dev_list_lock);
493
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200494 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
495 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200496
497 kfree(rp);
498
499 return err;
500}
501
Marcel Holtmann96f14742015-03-14 19:27:57 -0700502static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
503 void *data, u16 data_len)
504{
505 struct mgmt_rp_read_ext_index_list *rp;
506 struct hci_dev *d;
507 size_t rp_len;
508 u16 count;
509 int err;
510
511 BT_DBG("sock %p", sk);
512
513 read_lock(&hci_dev_list_lock);
514
515 count = 0;
516 list_for_each_entry(d, &hci_dev_list, list) {
517 if (d->dev_type == HCI_BREDR || d->dev_type == HCI_AMP)
518 count++;
519 }
520
521 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
522 rp = kmalloc(rp_len, GFP_ATOMIC);
523 if (!rp) {
524 read_unlock(&hci_dev_list_lock);
525 return -ENOMEM;
526 }
527
528 count = 0;
529 list_for_each_entry(d, &hci_dev_list, list) {
530 if (hci_dev_test_flag(d, HCI_SETUP) ||
531 hci_dev_test_flag(d, HCI_CONFIG) ||
532 hci_dev_test_flag(d, HCI_USER_CHANNEL))
533 continue;
534
535 /* Devices marked as raw-only are neither configured
536 * nor unconfigured controllers.
537 */
538 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
539 continue;
540
541 if (d->dev_type == HCI_BREDR) {
542 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
543 rp->entry[count].type = 0x01;
544 else
545 rp->entry[count].type = 0x00;
546 } else if (d->dev_type == HCI_AMP) {
547 rp->entry[count].type = 0x02;
548 } else {
549 continue;
550 }
551
552 rp->entry[count].bus = d->bus;
553 rp->entry[count++].index = cpu_to_le16(d->id);
554 BT_DBG("Added hci%u", d->id);
555 }
556
557 rp->num_controllers = cpu_to_le16(count);
558 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
559
560 read_unlock(&hci_dev_list_lock);
561
562 /* If this command is called at least once, then all the
563 * default index and unconfigured index events are disabled
564 * and from now on only extended index events are used.
565 */
566 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
567 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
568 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
569
570 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
571 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
572
573 kfree(rp);
574
575 return err;
576}
577
Marcel Holtmanndbece372014-07-04 18:11:55 +0200578static bool is_configured(struct hci_dev *hdev)
579{
580 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700581 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200582 return false;
583
584 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
585 !bacmp(&hdev->public_addr, BDADDR_ANY))
586 return false;
587
588 return true;
589}
590
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200591static __le32 get_missing_options(struct hci_dev *hdev)
592{
593 u32 options = 0;
594
Marcel Holtmanndbece372014-07-04 18:11:55 +0200595 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700596 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200597 options |= MGMT_OPTION_EXTERNAL_CONFIG;
598
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200599 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
600 !bacmp(&hdev->public_addr, BDADDR_ANY))
601 options |= MGMT_OPTION_PUBLIC_ADDRESS;
602
603 return cpu_to_le32(options);
604}
605
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200606static int new_options(struct hci_dev *hdev, struct sock *skip)
607{
608 __le32 options = get_missing_options(hdev);
609
610 return mgmt_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
611 sizeof(options), skip);
612}
613
Marcel Holtmanndbece372014-07-04 18:11:55 +0200614static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
615{
616 __le32 options = get_missing_options(hdev);
617
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200618 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
619 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200620}
621
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200622static int read_config_info(struct sock *sk, struct hci_dev *hdev,
623 void *data, u16 data_len)
624{
625 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200626 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200627
628 BT_DBG("sock %p %s", sk, hdev->name);
629
630 hci_dev_lock(hdev);
631
632 memset(&rp, 0, sizeof(rp));
633 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200634
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200635 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
636 options |= MGMT_OPTION_EXTERNAL_CONFIG;
637
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200638 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200639 options |= MGMT_OPTION_PUBLIC_ADDRESS;
640
641 rp.supported_options = cpu_to_le32(options);
642 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200643
644 hci_dev_unlock(hdev);
645
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200646 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
647 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200648}
649
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200650static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200651{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200652 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200653
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200654 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300655 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800656 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300657 settings |= MGMT_SETTING_CONNECTABLE;
658 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200659
Andre Guedesed3fa312012-07-24 15:03:46 -0300660 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500661 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
662 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200663 settings |= MGMT_SETTING_BREDR;
664 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700665
666 if (lmp_ssp_capable(hdev)) {
667 settings |= MGMT_SETTING_SSP;
668 settings |= MGMT_SETTING_HS;
669 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800670
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800671 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800672 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700673 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100674
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300675 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200676 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300677 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300678 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200679 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800680 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300681 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200682
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200683 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
684 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200685 settings |= MGMT_SETTING_CONFIGURATION;
686
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200687 return settings;
688}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200689
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200690static u32 get_current_settings(struct hci_dev *hdev)
691{
692 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200693
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200694 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100695 settings |= MGMT_SETTING_POWERED;
696
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700697 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200698 settings |= MGMT_SETTING_CONNECTABLE;
699
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700700 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500701 settings |= MGMT_SETTING_FAST_CONNECTABLE;
702
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700703 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200704 settings |= MGMT_SETTING_DISCOVERABLE;
705
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700706 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300707 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200708
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700709 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200710 settings |= MGMT_SETTING_BREDR;
711
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700712 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200713 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200714
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700715 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200716 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200717
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700718 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200719 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200720
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700721 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200722 settings |= MGMT_SETTING_HS;
723
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700724 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300725 settings |= MGMT_SETTING_ADVERTISING;
726
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700727 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800728 settings |= MGMT_SETTING_SECURE_CONN;
729
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700730 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800731 settings |= MGMT_SETTING_DEBUG_KEYS;
732
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700733 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200734 settings |= MGMT_SETTING_PRIVACY;
735
Marcel Holtmann93690c22015-03-06 10:11:21 -0800736 /* The current setting for static address has two purposes. The
737 * first is to indicate if the static address will be used and
738 * the second is to indicate if it is actually set.
739 *
740 * This means if the static address is not configured, this flag
741 * will never bet set. If the address is configured, then if the
742 * address is actually used decides if the flag is set or not.
743 *
744 * For single mode LE only controllers and dual-mode controllers
745 * with BR/EDR disabled, the existence of the static address will
746 * be evaluated.
747 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700748 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700749 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800750 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
751 if (bacmp(&hdev->static_addr, BDADDR_ANY))
752 settings |= MGMT_SETTING_STATIC_ADDRESS;
753 }
754
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200755 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200756}
757
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300758#define PNP_INFO_SVCLASS_ID 0x1200
759
Johan Hedberg213202e2013-01-27 00:31:33 +0200760static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
761{
762 u8 *ptr = data, *uuids_start = NULL;
763 struct bt_uuid *uuid;
764
765 if (len < 4)
766 return ptr;
767
768 list_for_each_entry(uuid, &hdev->uuids, list) {
769 u16 uuid16;
770
771 if (uuid->size != 16)
772 continue;
773
774 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
775 if (uuid16 < 0x1100)
776 continue;
777
778 if (uuid16 == PNP_INFO_SVCLASS_ID)
779 continue;
780
781 if (!uuids_start) {
782 uuids_start = ptr;
783 uuids_start[0] = 1;
784 uuids_start[1] = EIR_UUID16_ALL;
785 ptr += 2;
786 }
787
788 /* Stop if not enough space to put next UUID */
789 if ((ptr - data) + sizeof(u16) > len) {
790 uuids_start[1] = EIR_UUID16_SOME;
791 break;
792 }
793
794 *ptr++ = (uuid16 & 0x00ff);
795 *ptr++ = (uuid16 & 0xff00) >> 8;
796 uuids_start[0] += sizeof(uuid16);
797 }
798
799 return ptr;
800}
801
Johan Hedbergcdf19632013-01-27 00:31:34 +0200802static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
803{
804 u8 *ptr = data, *uuids_start = NULL;
805 struct bt_uuid *uuid;
806
807 if (len < 6)
808 return ptr;
809
810 list_for_each_entry(uuid, &hdev->uuids, list) {
811 if (uuid->size != 32)
812 continue;
813
814 if (!uuids_start) {
815 uuids_start = ptr;
816 uuids_start[0] = 1;
817 uuids_start[1] = EIR_UUID32_ALL;
818 ptr += 2;
819 }
820
821 /* Stop if not enough space to put next UUID */
822 if ((ptr - data) + sizeof(u32) > len) {
823 uuids_start[1] = EIR_UUID32_SOME;
824 break;
825 }
826
827 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
828 ptr += sizeof(u32);
829 uuids_start[0] += sizeof(u32);
830 }
831
832 return ptr;
833}
834
Johan Hedbergc00d5752013-01-27 00:31:35 +0200835static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
836{
837 u8 *ptr = data, *uuids_start = NULL;
838 struct bt_uuid *uuid;
839
840 if (len < 18)
841 return ptr;
842
843 list_for_each_entry(uuid, &hdev->uuids, list) {
844 if (uuid->size != 128)
845 continue;
846
847 if (!uuids_start) {
848 uuids_start = ptr;
849 uuids_start[0] = 1;
850 uuids_start[1] = EIR_UUID128_ALL;
851 ptr += 2;
852 }
853
854 /* Stop if not enough space to put next UUID */
855 if ((ptr - data) + 16 > len) {
856 uuids_start[1] = EIR_UUID128_SOME;
857 break;
858 }
859
860 memcpy(ptr, uuid->uuid, 16);
861 ptr += 16;
862 uuids_start[0] += 16;
863 }
864
865 return ptr;
866}
867
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200868static struct mgmt_pending_cmd *mgmt_pending_find(u16 opcode,
869 struct hci_dev *hdev)
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300870{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200871 struct mgmt_pending_cmd *cmd;
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300872
873 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
874 if (cmd->opcode == opcode)
875 return cmd;
876 }
877
878 return NULL;
879}
880
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200881static struct mgmt_pending_cmd *mgmt_pending_find_data(u16 opcode,
882 struct hci_dev *hdev,
883 const void *data)
Johan Hedberg95868422014-06-28 17:54:07 +0300884{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200885 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +0300886
887 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
888 if (cmd->user_data != data)
889 continue;
890 if (cmd->opcode == opcode)
891 return cmd;
892 }
893
894 return NULL;
895}
896
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700897static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
898{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700899 u8 ad_len = 0;
900 size_t name_len;
901
902 name_len = strlen(hdev->dev_name);
903 if (name_len > 0) {
904 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
905
906 if (name_len > max_len) {
907 name_len = max_len;
908 ptr[1] = EIR_NAME_SHORT;
909 } else
910 ptr[1] = EIR_NAME_COMPLETE;
911
912 ptr[0] = name_len + 1;
913
914 memcpy(ptr + 2, hdev->dev_name, name_len);
915
916 ad_len += (name_len + 2);
917 ptr += (name_len + 2);
918 }
919
920 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700921}
922
923static void update_scan_rsp_data(struct hci_request *req)
924{
925 struct hci_dev *hdev = req->hdev;
926 struct hci_cp_le_set_scan_rsp_data cp;
927 u8 len;
928
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700929 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700930 return;
931
932 memset(&cp, 0, sizeof(cp));
933
934 len = create_scan_rsp_data(hdev, cp.data);
935
Johan Hedbergeb438b52013-10-16 15:31:07 +0300936 if (hdev->scan_rsp_data_len == len &&
937 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700938 return;
939
Johan Hedbergeb438b52013-10-16 15:31:07 +0300940 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
941 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700942
943 cp.length = len;
944
945 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
946}
947
Johan Hedberg9a43e252013-10-20 19:00:07 +0300948static u8 get_adv_discov_flags(struct hci_dev *hdev)
949{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200950 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300951
952 /* If there's a pending mgmt command the flags will not yet have
953 * their final values, so check for this first.
954 */
955 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
956 if (cmd) {
957 struct mgmt_mode *cp = cmd->param;
958 if (cp->val == 0x01)
959 return LE_AD_GENERAL;
960 else if (cp->val == 0x02)
961 return LE_AD_LIMITED;
962 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700963 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300964 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700965 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300966 return LE_AD_GENERAL;
967 }
968
969 return 0;
970}
971
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700972static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700973{
974 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700975
Johan Hedberg9a43e252013-10-20 19:00:07 +0300976 flags |= get_adv_discov_flags(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700977
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700978 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700979 flags |= LE_AD_NO_BREDR;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700980
981 if (flags) {
982 BT_DBG("adv flags 0x%02x", flags);
983
984 ptr[0] = 2;
985 ptr[1] = EIR_FLAGS;
986 ptr[2] = flags;
987
988 ad_len += 3;
989 ptr += 3;
990 }
991
992 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
993 ptr[0] = 2;
994 ptr[1] = EIR_TX_POWER;
995 ptr[2] = (u8) hdev->adv_tx_power;
996
997 ad_len += 3;
998 ptr += 3;
999 }
1000
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001001 return ad_len;
1002}
1003
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001004static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001005{
1006 struct hci_dev *hdev = req->hdev;
1007 struct hci_cp_le_set_adv_data cp;
1008 u8 len;
1009
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001010 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001011 return;
1012
1013 memset(&cp, 0, sizeof(cp));
1014
Marcel Holtmann46cad2e2013-10-16 00:16:46 -07001015 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001016
1017 if (hdev->adv_data_len == len &&
1018 memcmp(cp.data, hdev->adv_data, len) == 0)
1019 return;
1020
1021 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
1022 hdev->adv_data_len = len;
1023
1024 cp.length = len;
1025
1026 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
1027}
1028
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001029int mgmt_update_adv_data(struct hci_dev *hdev)
1030{
1031 struct hci_request req;
1032
1033 hci_req_init(&req, hdev);
1034 update_adv_data(&req);
1035
1036 return hci_req_run(&req, NULL);
1037}
1038
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001039static void create_eir(struct hci_dev *hdev, u8 *data)
1040{
1041 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001042 size_t name_len;
1043
1044 name_len = strlen(hdev->dev_name);
1045
1046 if (name_len > 0) {
1047 /* EIR Data type */
1048 if (name_len > 48) {
1049 name_len = 48;
1050 ptr[1] = EIR_NAME_SHORT;
1051 } else
1052 ptr[1] = EIR_NAME_COMPLETE;
1053
1054 /* EIR Data length */
1055 ptr[0] = name_len + 1;
1056
1057 memcpy(ptr + 2, hdev->dev_name, name_len);
1058
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001059 ptr += (name_len + 2);
1060 }
1061
Johan Hedbergbbaf4442012-11-08 01:22:59 +01001062 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -07001063 ptr[0] = 2;
1064 ptr[1] = EIR_TX_POWER;
1065 ptr[2] = (u8) hdev->inq_tx_power;
1066
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -07001067 ptr += 3;
1068 }
1069
Marcel Holtmann2b9be132012-03-11 19:32:12 -07001070 if (hdev->devid_source > 0) {
1071 ptr[0] = 9;
1072 ptr[1] = EIR_DEVICE_ID;
1073
1074 put_unaligned_le16(hdev->devid_source, ptr + 2);
1075 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
1076 put_unaligned_le16(hdev->devid_product, ptr + 6);
1077 put_unaligned_le16(hdev->devid_version, ptr + 8);
1078
Marcel Holtmann2b9be132012-03-11 19:32:12 -07001079 ptr += 10;
1080 }
1081
Johan Hedberg213202e2013-01-27 00:31:33 +02001082 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +02001083 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +02001084 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001085}
1086
Johan Hedberg890ea892013-03-15 17:06:52 -05001087static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001088{
Johan Hedberg890ea892013-03-15 17:06:52 -05001089 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001090 struct hci_cp_write_eir cp;
1091
Johan Hedberg504c8dc2012-02-23 13:30:41 +02001092 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001093 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +02001094
Johan Hedberg976eb202012-10-24 21:12:01 +03001095 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001096 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001097
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001098 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg890ea892013-03-15 17:06:52 -05001099 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001100
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001101 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -05001102 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001103
1104 memset(&cp, 0, sizeof(cp));
1105
1106 create_eir(hdev, cp.data);
1107
1108 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -05001109 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001110
1111 memcpy(hdev->eir, cp.data, sizeof(cp.data));
1112
Johan Hedberg890ea892013-03-15 17:06:52 -05001113 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001114}
1115
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001116static u8 get_service_classes(struct hci_dev *hdev)
1117{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -03001118 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001119 u8 val = 0;
1120
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -03001121 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001122 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001123
1124 return val;
1125}
1126
Johan Hedberg890ea892013-03-15 17:06:52 -05001127static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001128{
Johan Hedberg890ea892013-03-15 17:06:52 -05001129 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001130 u8 cod[3];
1131
1132 BT_DBG("%s", hdev->name);
1133
Johan Hedberg504c8dc2012-02-23 13:30:41 +02001134 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001135 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +02001136
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001137 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedbergf87ea1d2013-10-19 23:38:17 +03001138 return;
1139
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001140 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -05001141 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001142
1143 cod[0] = hdev->minor_class;
1144 cod[1] = hdev->major_class;
1145 cod[2] = get_service_classes(hdev);
1146
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001147 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Marcel Holtmann6acd7db2013-10-15 06:33:53 -07001148 cod[1] |= 0x20;
1149
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001150 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -05001151 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001152
Johan Hedberg890ea892013-03-15 17:06:52 -05001153 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001154}
1155
Johan Hedberga4858cb2014-02-25 19:56:31 +02001156static bool get_connectable(struct hci_dev *hdev)
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001157{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001158 struct mgmt_pending_cmd *cmd;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001159
1160 /* If there's a pending mgmt command the flag will not yet have
1161 * it's final value, so check for this first.
1162 */
1163 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1164 if (cmd) {
1165 struct mgmt_mode *cp = cmd->param;
Johan Hedberga4858cb2014-02-25 19:56:31 +02001166 return cp->val;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001167 }
1168
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001169 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001170}
1171
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001172static void disable_advertising(struct hci_request *req)
1173{
1174 u8 enable = 0x00;
1175
1176 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1177}
1178
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001179static void enable_advertising(struct hci_request *req)
1180{
1181 struct hci_dev *hdev = req->hdev;
1182 struct hci_cp_le_set_adv_param cp;
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001183 u8 own_addr_type, enable = 0x01;
Johan Hedberga4858cb2014-02-25 19:56:31 +02001184 bool connectable;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001185
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001186 if (hci_conn_num(hdev, LE_LINK) > 0)
1187 return;
1188
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001189 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001190 disable_advertising(req);
1191
Johan Hedberg5ce194c2014-07-08 15:07:49 +03001192 /* Clear the HCI_LE_ADV bit temporarily so that the
Johan Hedberg8d972502014-02-28 12:54:14 +02001193 * hci_update_random_address knows that it's safe to go ahead
1194 * and write a new random address. The flag will be set back on
1195 * as soon as the SET_ADV_ENABLE HCI command completes.
1196 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001197 hci_dev_clear_flag(hdev, HCI_LE_ADV);
Johan Hedberg8d972502014-02-28 12:54:14 +02001198
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001199 if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07001200 connectable = true;
1201 else
1202 connectable = get_connectable(hdev);
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001203
Johan Hedberga4858cb2014-02-25 19:56:31 +02001204 /* Set require_privacy to true only when non-connectable
1205 * advertising is used. In that case it is fine to use a
1206 * non-resolvable private address.
1207 */
1208 if (hci_update_random_address(req, !connectable, &own_addr_type) < 0)
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001209 return;
1210
Marcel Holtmann41c90c12014-02-23 20:25:55 -08001211 memset(&cp, 0, sizeof(cp));
Georg Lukas628531c2014-07-26 13:59:57 +02001212 cp.min_interval = cpu_to_le16(hdev->le_adv_min_interval);
1213 cp.max_interval = cpu_to_le16(hdev->le_adv_max_interval);
Johan Hedberga4858cb2014-02-25 19:56:31 +02001214 cp.type = connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001215 cp.own_address_type = own_addr_type;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001216 cp.channel_map = hdev->le_adv_channel_map;
1217
1218 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1219
1220 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1221}
1222
Johan Hedberg7d785252011-12-15 00:47:39 +02001223static void service_cache_off(struct work_struct *work)
1224{
1225 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001226 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -05001227 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +02001228
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001229 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +02001230 return;
1231
Johan Hedberg890ea892013-03-15 17:06:52 -05001232 hci_req_init(&req, hdev);
1233
Johan Hedberg7d785252011-12-15 00:47:39 +02001234 hci_dev_lock(hdev);
1235
Johan Hedberg890ea892013-03-15 17:06:52 -05001236 update_eir(&req);
1237 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001238
1239 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001240
1241 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +02001242}
1243
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001244static void rpa_expired(struct work_struct *work)
1245{
1246 struct hci_dev *hdev = container_of(work, struct hci_dev,
1247 rpa_expired.work);
1248 struct hci_request req;
1249
1250 BT_DBG("");
1251
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001252 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001253
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001254 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001255 return;
1256
1257 /* The generation of a new RPA and programming it into the
1258 * controller happens in the enable_advertising() function.
1259 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001260 hci_req_init(&req, hdev);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001261 enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001262 hci_req_run(&req, NULL);
1263}
1264
Johan Hedberg6a919082012-02-28 06:17:26 +02001265static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +02001266{
Marcel Holtmann238be782015-03-13 02:11:06 -07001267 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +02001268 return;
1269
Johan Hedberg4f87da82012-03-02 19:55:56 +02001270 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001271 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +02001272
Johan Hedberg4f87da82012-03-02 19:55:56 +02001273 /* Non-mgmt controlled devices get this bit set
1274 * implicitly so that pairing works for them, however
1275 * for mgmt we require user-space to explicitly enable
1276 * it
1277 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001278 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +02001279}
1280
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001281static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001282 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001283{
1284 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001285
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001286 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001287
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001288 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001289
Johan Hedberg03811012010-12-08 00:21:06 +02001290 memset(&rp, 0, sizeof(rp));
1291
Johan Hedberg03811012010-12-08 00:21:06 +02001292 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001293
1294 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001295 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001296
1297 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1298 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1299
1300 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +02001301
1302 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001303 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +02001304
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001305 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001306
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001307 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1308 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +02001309}
1310
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001311static void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
Johan Hedberg03811012010-12-08 00:21:06 +02001312{
1313 sock_put(cmd->sk);
1314 kfree(cmd->param);
1315 kfree(cmd);
1316}
1317
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001318static struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
1319 struct hci_dev *hdev,
1320 void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001321{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001322 struct mgmt_pending_cmd *cmd;
Johan Hedberg03811012010-12-08 00:21:06 +02001323
Johan Hedbergfca20012014-06-28 17:54:05 +03001324 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001325 if (!cmd)
1326 return NULL;
1327
1328 cmd->opcode = opcode;
1329 cmd->index = hdev->id;
1330
Johan Hedberg323b0b82014-12-05 13:36:01 +02001331 cmd->param = kmemdup(data, len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001332 if (!cmd->param) {
1333 kfree(cmd);
1334 return NULL;
1335 }
1336
Johan Hedberg323b0b82014-12-05 13:36:01 +02001337 cmd->param_len = len;
Johan Hedberg03811012010-12-08 00:21:06 +02001338
1339 cmd->sk = sk;
1340 sock_hold(sk);
1341
1342 list_add(&cmd->list, &hdev->mgmt_pending);
1343
1344 return cmd;
1345}
1346
1347static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001348 void (*cb)(struct mgmt_pending_cmd *cmd,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001349 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001350 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02001351{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001352 struct mgmt_pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +02001353
Andre Guedesa3d09352013-02-01 11:21:30 -03001354 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +02001355 if (opcode > 0 && cmd->opcode != opcode)
1356 continue;
1357
1358 cb(cmd, data);
1359 }
1360}
1361
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001362static void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
Johan Hedberg03811012010-12-08 00:21:06 +02001363{
1364 list_del(&cmd->list);
1365 mgmt_pending_free(cmd);
1366}
1367
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001368static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001369{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001370 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001371
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001372 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1373 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001374}
1375
Marcel Holtmann1904a852015-01-11 13:50:44 -08001376static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001377{
1378 BT_DBG("%s status 0x%02x", hdev->name, status);
1379
Johan Hedberga3172b72014-02-28 09:33:44 +02001380 if (hci_conn_count(hdev) == 0) {
1381 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001382 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001383 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001384}
1385
Johan Hedberg23a48092014-07-08 16:05:06 +03001386static bool hci_stop_discovery(struct hci_request *req)
Johan Hedberg21a60d32014-06-10 14:05:58 +03001387{
1388 struct hci_dev *hdev = req->hdev;
1389 struct hci_cp_remote_name_req_cancel cp;
1390 struct inquiry_entry *e;
1391
1392 switch (hdev->discovery.state) {
1393 case DISCOVERY_FINDING:
1394 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
1395 hci_req_add(req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
1396 } else {
1397 cancel_delayed_work(&hdev->le_scan_disable);
1398 hci_req_add_le_scan_disable(req);
1399 }
1400
Johan Hedberg23a48092014-07-08 16:05:06 +03001401 return true;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001402
1403 case DISCOVERY_RESOLVING:
1404 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
1405 NAME_PENDING);
1406 if (!e)
Johan Hedberg23a48092014-07-08 16:05:06 +03001407 break;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001408
1409 bacpy(&cp.bdaddr, &e->data.bdaddr);
1410 hci_req_add(req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
1411 &cp);
1412
Johan Hedberg23a48092014-07-08 16:05:06 +03001413 return true;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001414
1415 default:
1416 /* Passive scanning */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001417 if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
Johan Hedberg21a60d32014-06-10 14:05:58 +03001418 hci_req_add_le_scan_disable(req);
Johan Hedberg23a48092014-07-08 16:05:06 +03001419 return true;
1420 }
1421
Johan Hedberg21a60d32014-06-10 14:05:58 +03001422 break;
1423 }
Johan Hedberg23a48092014-07-08 16:05:06 +03001424
1425 return false;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001426}
1427
Johan Hedberg8b064a32014-02-24 14:52:22 +02001428static int clean_up_hci_state(struct hci_dev *hdev)
1429{
1430 struct hci_request req;
1431 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001432 bool discov_stopped;
1433 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001434
1435 hci_req_init(&req, hdev);
1436
1437 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1438 test_bit(HCI_PSCAN, &hdev->flags)) {
1439 u8 scan = 0x00;
1440 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1441 }
1442
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001443 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedberg8b064a32014-02-24 14:52:22 +02001444 disable_advertising(&req);
1445
Johan Hedberg23a48092014-07-08 16:05:06 +03001446 discov_stopped = hci_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001447
1448 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
1449 struct hci_cp_disconnect dc;
Johan Hedbergc9910d02014-02-27 14:35:12 +02001450 struct hci_cp_reject_conn_req rej;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001451
Johan Hedbergc9910d02014-02-27 14:35:12 +02001452 switch (conn->state) {
1453 case BT_CONNECTED:
1454 case BT_CONFIG:
1455 dc.handle = cpu_to_le16(conn->handle);
1456 dc.reason = 0x15; /* Terminated due to Power Off */
1457 hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1458 break;
1459 case BT_CONNECT:
1460 if (conn->type == LE_LINK)
1461 hci_req_add(&req, HCI_OP_LE_CREATE_CONN_CANCEL,
1462 0, NULL);
1463 else if (conn->type == ACL_LINK)
1464 hci_req_add(&req, HCI_OP_CREATE_CONN_CANCEL,
1465 6, &conn->dst);
1466 break;
1467 case BT_CONNECT2:
1468 bacpy(&rej.bdaddr, &conn->dst);
1469 rej.reason = 0x15; /* Terminated due to Power Off */
1470 if (conn->type == ACL_LINK)
1471 hci_req_add(&req, HCI_OP_REJECT_CONN_REQ,
1472 sizeof(rej), &rej);
1473 else if (conn->type == SCO_LINK)
1474 hci_req_add(&req, HCI_OP_REJECT_SYNC_CONN_REQ,
1475 sizeof(rej), &rej);
1476 break;
1477 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001478 }
1479
Johan Hedberg23a48092014-07-08 16:05:06 +03001480 err = hci_req_run(&req, clean_up_hci_complete);
1481 if (!err && discov_stopped)
1482 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1483
1484 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001485}
1486
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001487static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001488 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001489{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001490 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001491 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001492 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001493
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001494 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001495
Johan Hedberga7e80f22013-01-09 16:05:19 +02001496 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001497 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1498 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001499
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001500 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001501
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001502 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001503 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1504 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001505 goto failed;
1506 }
1507
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001508 if (hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001509 cancel_delayed_work(&hdev->power_off);
1510
1511 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +02001512 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
1513 data, len);
1514 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001515 goto failed;
1516 }
1517 }
1518
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001519 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001520 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001521 goto failed;
1522 }
1523
Johan Hedberg03811012010-12-08 00:21:06 +02001524 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1525 if (!cmd) {
1526 err = -ENOMEM;
1527 goto failed;
1528 }
1529
Johan Hedberg8b064a32014-02-24 14:52:22 +02001530 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001531 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001532 err = 0;
1533 } else {
1534 /* Disconnect connections, stop scans, etc */
1535 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001536 if (!err)
1537 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1538 HCI_POWER_OFF_TIMEOUT);
Johan Hedberg03811012010-12-08 00:21:06 +02001539
Johan Hedberg8b064a32014-02-24 14:52:22 +02001540 /* ENODATA means there were no HCI commands queued */
1541 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001542 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001543 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1544 err = 0;
1545 }
1546 }
Johan Hedberg03811012010-12-08 00:21:06 +02001547
1548failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001549 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001550 return err;
1551}
1552
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001553static int new_settings(struct hci_dev *hdev, struct sock *skip)
1554{
1555 __le32 ev;
1556
1557 ev = cpu_to_le32(get_current_settings(hdev));
1558
1559 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1560}
1561
Johan Hedberg91a668b2014-07-09 13:28:26 +03001562int mgmt_new_settings(struct hci_dev *hdev)
1563{
1564 return new_settings(hdev, NULL);
1565}
1566
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001567struct cmd_lookup {
1568 struct sock *sk;
1569 struct hci_dev *hdev;
1570 u8 mgmt_status;
1571};
1572
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001573static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001574{
1575 struct cmd_lookup *match = data;
1576
1577 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1578
1579 list_del(&cmd->list);
1580
1581 if (match->sk == NULL) {
1582 match->sk = cmd->sk;
1583 sock_hold(match->sk);
1584 }
1585
1586 mgmt_pending_free(cmd);
1587}
1588
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001589static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001590{
1591 u8 *status = data;
1592
Johan Hedberga69e8372015-03-06 21:08:53 +02001593 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001594 mgmt_pending_remove(cmd);
1595}
1596
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001597static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001598{
1599 if (cmd->cmd_complete) {
1600 u8 *status = data;
1601
1602 cmd->cmd_complete(cmd, *status);
1603 mgmt_pending_remove(cmd);
1604
1605 return;
1606 }
1607
1608 cmd_status_rsp(cmd, data);
1609}
1610
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001611static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001612{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001613 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1614 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001615}
1616
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001617static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001618{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001619 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1620 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001621}
1622
Johan Hedberge6fe7982013-10-02 15:45:22 +03001623static u8 mgmt_bredr_support(struct hci_dev *hdev)
1624{
1625 if (!lmp_bredr_capable(hdev))
1626 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001627 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001628 return MGMT_STATUS_REJECTED;
1629 else
1630 return MGMT_STATUS_SUCCESS;
1631}
1632
1633static u8 mgmt_le_support(struct hci_dev *hdev)
1634{
1635 if (!lmp_le_capable(hdev))
1636 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001637 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001638 return MGMT_STATUS_REJECTED;
1639 else
1640 return MGMT_STATUS_SUCCESS;
1641}
1642
Marcel Holtmann1904a852015-01-11 13:50:44 -08001643static void set_discoverable_complete(struct hci_dev *hdev, u8 status,
1644 u16 opcode)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001645{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001646 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001647 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001648 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001649 bool changed;
1650
1651 BT_DBG("status 0x%02x", status);
1652
1653 hci_dev_lock(hdev);
1654
1655 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1656 if (!cmd)
1657 goto unlock;
1658
1659 if (status) {
1660 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001661 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001662 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001663 goto remove_cmd;
1664 }
1665
1666 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001667 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001668 changed = !hci_dev_test_and_set_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001669
1670 if (hdev->discov_timeout > 0) {
1671 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1672 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1673 to);
1674 }
1675 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001676 changed = hci_dev_test_and_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001677 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001678
1679 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1680
1681 if (changed)
1682 new_settings(hdev, cmd->sk);
1683
Marcel Holtmann970ba522013-10-15 06:33:57 -07001684 /* When the discoverable mode gets changed, make sure
1685 * that class of device has the limited discoverable
Johan Hedberg432df052014-08-01 11:13:31 +03001686 * bit correctly set. Also update page scan based on whitelist
1687 * entries.
Marcel Holtmann970ba522013-10-15 06:33:57 -07001688 */
1689 hci_req_init(&req, hdev);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001690 __hci_update_page_scan(&req);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001691 update_class(&req);
1692 hci_req_run(&req, NULL);
1693
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001694remove_cmd:
1695 mgmt_pending_remove(cmd);
1696
1697unlock:
1698 hci_dev_unlock(hdev);
1699}
1700
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001701static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001702 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001703{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001704 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001705 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001706 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001707 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001708 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001709 int err;
Johan Hedberge41d8b42010-12-13 21:07:03 +02001710
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001711 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001712
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001713 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1714 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001715 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1716 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001717
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001718 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001719 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1720 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001721
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001722 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001723
1724 /* Disabling discoverable requires that no timeout is set,
1725 * and enabling limited discoverable requires a timeout.
1726 */
1727 if ((cp->val == 0x00 && timeout > 0) ||
1728 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001729 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1730 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001731
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001732 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001733
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001734 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001735 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1736 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001737 goto failed;
1738 }
1739
1740 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001741 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001742 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1743 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001744 goto failed;
1745 }
1746
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001747 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001748 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1749 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001750 goto failed;
1751 }
1752
1753 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001754 bool changed = false;
1755
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001756 /* Setting limited discoverable when powered off is
1757 * not a valid operation since it requires a timeout
1758 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1759 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001760 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001761 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001762 changed = true;
1763 }
1764
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001765 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001766 if (err < 0)
1767 goto failed;
1768
1769 if (changed)
1770 err = new_settings(hdev, sk);
1771
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001772 goto failed;
1773 }
1774
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001775 /* If the current mode is the same, then just update the timeout
1776 * value with the new value. And if only the timeout gets updated,
1777 * then no need for any HCI transactions.
1778 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001779 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1780 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1781 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001782 cancel_delayed_work(&hdev->discov_off);
1783 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001784
Marcel Holtmann36261542013-10-15 08:28:51 -07001785 if (cp->val && hdev->discov_timeout > 0) {
1786 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001787 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001788 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001789 }
1790
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001791 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001792 goto failed;
1793 }
1794
1795 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1796 if (!cmd) {
1797 err = -ENOMEM;
1798 goto failed;
1799 }
1800
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001801 /* Cancel any potential discoverable timeout that might be
1802 * still active and store new timeout value. The arming of
1803 * the timeout happens in the complete handler.
1804 */
1805 cancel_delayed_work(&hdev->discov_off);
1806 hdev->discov_timeout = timeout;
1807
Johan Hedbergb456f872013-10-19 23:38:22 +03001808 /* Limited discoverable mode */
1809 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001810 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001811 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001812 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001813
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001814 hci_req_init(&req, hdev);
1815
Johan Hedberg9a43e252013-10-20 19:00:07 +03001816 /* The procedure for LE-only controllers is much simpler - just
1817 * update the advertising data.
1818 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001819 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg9a43e252013-10-20 19:00:07 +03001820 goto update_ad;
1821
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001822 scan = SCAN_PAGE;
1823
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001824 if (cp->val) {
1825 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001826
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001827 if (cp->val == 0x02) {
1828 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001829 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001830 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1831 hci_cp.iac_lap[1] = 0x8b;
1832 hci_cp.iac_lap[2] = 0x9e;
1833 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1834 hci_cp.iac_lap[4] = 0x8b;
1835 hci_cp.iac_lap[5] = 0x9e;
1836 } else {
1837 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001838 hci_cp.num_iac = 1;
1839 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1840 hci_cp.iac_lap[1] = 0x8b;
1841 hci_cp.iac_lap[2] = 0x9e;
1842 }
1843
1844 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1845 (hci_cp.num_iac * 3) + 1, &hci_cp);
1846
1847 scan |= SCAN_INQUIRY;
1848 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001849 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001850 }
1851
1852 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001853
Johan Hedberg9a43e252013-10-20 19:00:07 +03001854update_ad:
1855 update_adv_data(&req);
1856
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001857 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001858 if (err < 0)
1859 mgmt_pending_remove(cmd);
1860
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001861failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001862 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001863 return err;
1864}
1865
Johan Hedberg406d7802013-03-15 17:07:09 -05001866static void write_fast_connectable(struct hci_request *req, bool enable)
1867{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001868 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001869 struct hci_cp_write_page_scan_activity acp;
1870 u8 type;
1871
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001872 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg547003b2013-10-21 16:51:53 +03001873 return;
1874
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001875 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1876 return;
1877
Johan Hedberg406d7802013-03-15 17:07:09 -05001878 if (enable) {
1879 type = PAGE_SCAN_TYPE_INTERLACED;
1880
1881 /* 160 msec page scan interval */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001882 acp.interval = cpu_to_le16(0x0100);
Johan Hedberg406d7802013-03-15 17:07:09 -05001883 } else {
1884 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1885
1886 /* default 1.28 sec page scan */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001887 acp.interval = cpu_to_le16(0x0800);
Johan Hedberg406d7802013-03-15 17:07:09 -05001888 }
1889
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001890 acp.window = cpu_to_le16(0x0012);
Johan Hedberg406d7802013-03-15 17:07:09 -05001891
Johan Hedbergbd98b992013-03-15 17:07:13 -05001892 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1893 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1894 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1895 sizeof(acp), &acp);
1896
1897 if (hdev->page_scan_type != type)
1898 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001899}
1900
Marcel Holtmann1904a852015-01-11 13:50:44 -08001901static void set_connectable_complete(struct hci_dev *hdev, u8 status,
1902 u16 opcode)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001903{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001904 struct mgmt_pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001905 struct mgmt_mode *cp;
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001906 bool conn_changed, discov_changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001907
1908 BT_DBG("status 0x%02x", status);
1909
1910 hci_dev_lock(hdev);
1911
1912 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1913 if (!cmd)
1914 goto unlock;
1915
Johan Hedberg37438c12013-10-14 16:20:05 +03001916 if (status) {
1917 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001918 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001919 goto remove_cmd;
1920 }
1921
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001922 cp = cmd->param;
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001923 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001924 conn_changed = !hci_dev_test_and_set_flag(hdev,
1925 HCI_CONNECTABLE);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001926 discov_changed = false;
1927 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001928 conn_changed = hci_dev_test_and_clear_flag(hdev,
1929 HCI_CONNECTABLE);
1930 discov_changed = hci_dev_test_and_clear_flag(hdev,
1931 HCI_DISCOVERABLE);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001932 }
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001933
Johan Hedberg2b76f452013-03-15 17:07:04 -05001934 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1935
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001936 if (conn_changed || discov_changed) {
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001937 new_settings(hdev, cmd->sk);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001938 hci_update_page_scan(hdev);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001939 if (discov_changed)
1940 mgmt_update_adv_data(hdev);
Johan Hedberg2b7be332014-07-07 14:40:22 +03001941 hci_update_background_scan(hdev);
1942 }
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001943
Johan Hedberg37438c12013-10-14 16:20:05 +03001944remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001945 mgmt_pending_remove(cmd);
1946
1947unlock:
1948 hci_dev_unlock(hdev);
1949}
1950
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001951static int set_connectable_update_settings(struct hci_dev *hdev,
1952 struct sock *sk, u8 val)
1953{
1954 bool changed = false;
1955 int err;
1956
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001957 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001958 changed = true;
1959
1960 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001961 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001962 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001963 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1964 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001965 }
1966
1967 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1968 if (err < 0)
1969 return err;
1970
Johan Hedberg562064e2014-07-08 16:35:34 +03001971 if (changed) {
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001972 hci_update_page_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001973 hci_update_background_scan(hdev);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001974 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001975 }
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001976
1977 return 0;
1978}
1979
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001980static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001981 u16 len)
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001982{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001983 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001984 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001985 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001986 u8 scan;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001987 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001988
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001989 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001990
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001991 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1992 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001993 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1994 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001995
Johan Hedberga7e80f22013-01-09 16:05:19 +02001996 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001997 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1998 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001999
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002000 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002001
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002002 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03002003 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002004 goto failed;
2005 }
2006
2007 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002008 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002009 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
2010 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002011 goto failed;
2012 }
2013
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002014 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
2015 if (!cmd) {
2016 err = -ENOMEM;
2017 goto failed;
2018 }
2019
Johan Hedberg2b76f452013-03-15 17:07:04 -05002020 hci_req_init(&req, hdev);
2021
Johan Hedberg9a43e252013-10-20 19:00:07 +03002022 /* If BR/EDR is not enabled and we disable advertising as a
2023 * by-product of disabling connectable, we need to update the
2024 * advertising flags.
2025 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002026 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg9a43e252013-10-20 19:00:07 +03002027 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002028 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
2029 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg9a43e252013-10-20 19:00:07 +03002030 }
2031 update_adv_data(&req);
2032 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03002033 if (cp->val) {
2034 scan = SCAN_PAGE;
2035 } else {
Johan Hedberg3bd27242014-07-28 20:53:58 +03002036 /* If we don't have any whitelist entries just
2037 * disable all scanning. If there are entries
2038 * and we had both page and inquiry scanning
2039 * enabled then fall back to only page scanning.
2040 * Otherwise no changes are needed.
2041 */
2042 if (list_empty(&hdev->whitelist))
2043 scan = SCAN_DISABLED;
2044 else if (test_bit(HCI_ISCAN, &hdev->flags))
2045 scan = SCAN_PAGE;
2046 else
2047 goto no_scan_update;
Johan Hedberg9b742462013-10-14 16:20:03 +03002048
2049 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07002050 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03002051 cancel_delayed_work(&hdev->discov_off);
2052 }
2053
2054 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
2055 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05002056
Johan Hedberg3bd27242014-07-28 20:53:58 +03002057no_scan_update:
Johan Hedberge8b12022014-07-10 10:51:27 +03002058 /* Update the advertising parameters if necessary */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002059 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedberg1987fdc2013-10-14 21:15:24 +03002060 enable_advertising(&req);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03002061
Johan Hedberg2b76f452013-03-15 17:07:04 -05002062 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03002063 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002064 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03002065 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03002066 err = set_connectable_update_settings(hdev, sk,
2067 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03002068 goto failed;
2069 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002070
2071failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002072 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002073 return err;
2074}
2075
Johan Hedbergb2939472014-07-30 09:22:23 +03002076static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002077 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002078{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002079 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07002080 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002081 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002082
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002083 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002084
Johan Hedberga7e80f22013-01-09 16:05:19 +02002085 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002086 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
2087 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002088
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002089 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002090
2091 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07002092 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002093 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002094 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002095
Johan Hedbergb2939472014-07-30 09:22:23 +03002096 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002097 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07002098 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002099
Marcel Holtmann55594352013-10-06 16:11:57 -07002100 if (changed)
2101 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002102
Marcel Holtmann55594352013-10-06 16:11:57 -07002103unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002104 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002105 return err;
2106}
Johan Hedberg72a734e2010-12-30 00:38:22 +02002107
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002108static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
2109 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002110{
2111 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002112 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03002113 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002114 int err;
2115
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002116 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002117
Johan Hedberge6fe7982013-10-02 15:45:22 +03002118 status = mgmt_bredr_support(hdev);
2119 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002120 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2121 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03002122
Johan Hedberga7e80f22013-01-09 16:05:19 +02002123 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002124 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2125 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002126
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002127 hci_dev_lock(hdev);
2128
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002129 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02002130 bool changed = false;
2131
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002132 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07002133 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02002134 changed = true;
2135 }
2136
2137 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
2138 if (err < 0)
2139 goto failed;
2140
2141 if (changed)
2142 err = new_settings(hdev, sk);
2143
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002144 goto failed;
2145 }
2146
2147 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002148 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2149 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002150 goto failed;
2151 }
2152
2153 val = !!cp->val;
2154
2155 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
2156 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
2157 goto failed;
2158 }
2159
2160 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
2161 if (!cmd) {
2162 err = -ENOMEM;
2163 goto failed;
2164 }
2165
2166 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
2167 if (err < 0) {
2168 mgmt_pending_remove(cmd);
2169 goto failed;
2170 }
2171
2172failed:
2173 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002174 return err;
2175}
2176
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002177static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002178{
2179 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002180 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07002181 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002182 int err;
2183
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002184 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002185
Marcel Holtmanncdba5282013-10-02 21:31:52 -07002186 status = mgmt_bredr_support(hdev);
2187 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002188 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07002189
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002190 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002191 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2192 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002193
Johan Hedberga7e80f22013-01-09 16:05:19 +02002194 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002195 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2196 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002197
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002198 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02002199
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002200 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002201 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02002202
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002203 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07002204 changed = !hci_dev_test_and_set_flag(hdev,
2205 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002206 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002207 changed = hci_dev_test_and_clear_flag(hdev,
2208 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002209 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002210 changed = hci_dev_test_and_clear_flag(hdev,
2211 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002212 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002213 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02002214 }
2215
2216 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
2217 if (err < 0)
2218 goto failed;
2219
2220 if (changed)
2221 err = new_settings(hdev, sk);
2222
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002223 goto failed;
2224 }
2225
Johan Hedberg94d52da2015-02-19 17:38:06 +02002226 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002227 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2228 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002229 goto failed;
2230 }
2231
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002232 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002233 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
2234 goto failed;
2235 }
2236
2237 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
2238 if (!cmd) {
2239 err = -ENOMEM;
2240 goto failed;
2241 }
2242
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002243 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03002244 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
2245 sizeof(cp->val), &cp->val);
2246
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07002247 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002248 if (err < 0) {
2249 mgmt_pending_remove(cmd);
2250 goto failed;
2251 }
2252
2253failed:
2254 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002255 return err;
2256}
2257
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002258static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002259{
2260 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07002261 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03002262 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07002263 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002264
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002265 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002266
Johan Hedberge6fe7982013-10-02 15:45:22 +03002267 status = mgmt_bredr_support(hdev);
2268 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002269 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002270
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002271 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002272 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2273 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002274
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002275 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02002276 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2277 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002278
Johan Hedberga7e80f22013-01-09 16:05:19 +02002279 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002280 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2281 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002282
Marcel Holtmannee392692013-10-01 22:59:23 -07002283 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002284
Johan Hedberga2cb01d2015-02-19 17:38:07 +02002285 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002286 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2287 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02002288 goto unlock;
2289 }
2290
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002291 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07002292 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002293 } else {
2294 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002295 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2296 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002297 goto unlock;
2298 }
2299
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002300 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002301 }
Marcel Holtmannee392692013-10-01 22:59:23 -07002302
2303 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
2304 if (err < 0)
2305 goto unlock;
2306
2307 if (changed)
2308 err = new_settings(hdev, sk);
2309
2310unlock:
2311 hci_dev_unlock(hdev);
2312 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002313}
2314
Marcel Holtmann1904a852015-01-11 13:50:44 -08002315static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002316{
2317 struct cmd_lookup match = { NULL, hdev };
2318
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302319 hci_dev_lock(hdev);
2320
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002321 if (status) {
2322 u8 mgmt_err = mgmt_status(status);
2323
2324 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
2325 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302326 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002327 }
2328
2329 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
2330
2331 new_settings(hdev, match.sk);
2332
2333 if (match.sk)
2334 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002335
2336 /* Make sure the controller has a good default for
2337 * advertising data. Restrict the update to when LE
2338 * has actually been enabled. During power on, the
2339 * update in powered_update_hci will take care of it.
2340 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002341 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002342 struct hci_request req;
2343
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002344 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07002345 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07002346 update_scan_rsp_data(&req);
Johan Hedberg2cf22212014-12-19 22:26:00 +02002347 __hci_update_background_scan(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002348 hci_req_run(&req, NULL);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002349 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302350
2351unlock:
2352 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002353}
2354
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002355static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002356{
2357 struct mgmt_mode *cp = data;
2358 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002359 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002360 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002361 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002362 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002363
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002364 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002365
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002366 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002367 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2368 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002369
Johan Hedberga7e80f22013-01-09 16:05:19 +02002370 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002371 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2372 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002373
Johan Hedbergc73eee92013-04-19 18:35:21 +03002374 /* LE-only devices do not allow toggling LE on/off */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002375 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02002376 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2377 MGMT_STATUS_REJECTED);
Johan Hedbergc73eee92013-04-19 18:35:21 +03002378
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002379 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002380
2381 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02002382 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002383
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002384 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02002385 bool changed = false;
2386
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002387 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07002388 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002389 changed = true;
2390 }
2391
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002392 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002393 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03002394 changed = true;
2395 }
2396
Johan Hedberg06199cf2012-02-22 16:37:11 +02002397 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
2398 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08002399 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002400
2401 if (changed)
2402 err = new_settings(hdev, sk);
2403
Johan Hedberg1de028c2012-02-29 19:55:35 -08002404 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002405 }
2406
Johan Hedberg4375f102013-09-25 13:26:10 +03002407 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
2408 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002409 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2410 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002411 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002412 }
2413
2414 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
2415 if (!cmd) {
2416 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08002417 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002418 }
2419
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002420 hci_req_init(&req, hdev);
2421
Johan Hedberg06199cf2012-02-22 16:37:11 +02002422 memset(&hci_cp, 0, sizeof(hci_cp));
2423
2424 if (val) {
2425 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02002426 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002427 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002428 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002429 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002430 }
2431
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002432 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
2433 &hci_cp);
2434
2435 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05302436 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002437 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002438
Johan Hedberg1de028c2012-02-29 19:55:35 -08002439unlock:
2440 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002441 return err;
2442}
2443
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002444/* This is a helper function to test for pending mgmt commands that can
2445 * cause CoD or EIR HCI commands. We can only allow one such pending
2446 * mgmt command at a time since otherwise we cannot easily track what
2447 * the current values are, will be, and based on that calculate if a new
2448 * HCI command needs to be sent and if yes with what value.
2449 */
2450static bool pending_eir_or_class(struct hci_dev *hdev)
2451{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002452 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002453
2454 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2455 switch (cmd->opcode) {
2456 case MGMT_OP_ADD_UUID:
2457 case MGMT_OP_REMOVE_UUID:
2458 case MGMT_OP_SET_DEV_CLASS:
2459 case MGMT_OP_SET_POWERED:
2460 return true;
2461 }
2462 }
2463
2464 return false;
2465}
2466
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002467static const u8 bluetooth_base_uuid[] = {
2468 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2469 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2470};
2471
2472static u8 get_uuid_size(const u8 *uuid)
2473{
2474 u32 val;
2475
2476 if (memcmp(uuid, bluetooth_base_uuid, 12))
2477 return 128;
2478
2479 val = get_unaligned_le32(&uuid[12]);
2480 if (val > 0xffff)
2481 return 32;
2482
2483 return 16;
2484}
2485
Johan Hedberg92da6092013-03-15 17:06:55 -05002486static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2487{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002488 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002489
2490 hci_dev_lock(hdev);
2491
2492 cmd = mgmt_pending_find(mgmt_op, hdev);
2493 if (!cmd)
2494 goto unlock;
2495
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002496 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2497 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002498
2499 mgmt_pending_remove(cmd);
2500
2501unlock:
2502 hci_dev_unlock(hdev);
2503}
2504
Marcel Holtmann1904a852015-01-11 13:50:44 -08002505static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002506{
2507 BT_DBG("status 0x%02x", status);
2508
2509 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2510}
2511
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002512static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002513{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002514 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002515 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002516 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002517 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002518 int err;
2519
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002520 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002521
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002522 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002523
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002524 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002525 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2526 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002527 goto failed;
2528 }
2529
Andre Guedes92c4c202012-06-07 19:05:44 -03002530 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002531 if (!uuid) {
2532 err = -ENOMEM;
2533 goto failed;
2534 }
2535
2536 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002537 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002538 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002539
Johan Hedbergde66aa62013-01-27 00:31:27 +02002540 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002541
Johan Hedberg890ea892013-03-15 17:06:52 -05002542 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002543
Johan Hedberg890ea892013-03-15 17:06:52 -05002544 update_class(&req);
2545 update_eir(&req);
2546
Johan Hedberg92da6092013-03-15 17:06:55 -05002547 err = hci_req_run(&req, add_uuid_complete);
2548 if (err < 0) {
2549 if (err != -ENODATA)
2550 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002551
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002552 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2553 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002554 goto failed;
2555 }
2556
2557 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002558 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002559 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002560 goto failed;
2561 }
2562
2563 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002564
2565failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002566 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002567 return err;
2568}
2569
Johan Hedberg24b78d02012-02-23 23:24:30 +02002570static bool enable_service_cache(struct hci_dev *hdev)
2571{
2572 if (!hdev_is_powered(hdev))
2573 return false;
2574
Marcel Holtmann238be782015-03-13 02:11:06 -07002575 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002576 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2577 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002578 return true;
2579 }
2580
2581 return false;
2582}
2583
Marcel Holtmann1904a852015-01-11 13:50:44 -08002584static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002585{
2586 BT_DBG("status 0x%02x", status);
2587
2588 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2589}
2590
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002591static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002592 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002593{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002594 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002595 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002596 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002597 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 -05002598 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002599 int err, found;
2600
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002601 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002602
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002603 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002604
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002605 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002606 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2607 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002608 goto unlock;
2609 }
2610
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002611 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002612 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002613
Johan Hedberg24b78d02012-02-23 23:24:30 +02002614 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002615 err = mgmt_cmd_complete(sk, hdev->id,
2616 MGMT_OP_REMOVE_UUID,
2617 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002618 goto unlock;
2619 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002620
Johan Hedberg9246a862012-02-23 21:33:16 +02002621 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002622 }
2623
2624 found = 0;
2625
Johan Hedberg056341c2013-01-27 00:31:30 +02002626 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002627 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2628 continue;
2629
2630 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002631 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002632 found++;
2633 }
2634
2635 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002636 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2637 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002638 goto unlock;
2639 }
2640
Johan Hedberg9246a862012-02-23 21:33:16 +02002641update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002642 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002643
Johan Hedberg890ea892013-03-15 17:06:52 -05002644 update_class(&req);
2645 update_eir(&req);
2646
Johan Hedberg92da6092013-03-15 17:06:55 -05002647 err = hci_req_run(&req, remove_uuid_complete);
2648 if (err < 0) {
2649 if (err != -ENODATA)
2650 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002651
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002652 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2653 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002654 goto unlock;
2655 }
2656
2657 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002658 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002659 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002660 goto unlock;
2661 }
2662
2663 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002664
2665unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002666 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002667 return err;
2668}
2669
Marcel Holtmann1904a852015-01-11 13:50:44 -08002670static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002671{
2672 BT_DBG("status 0x%02x", status);
2673
2674 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2675}
2676
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002677static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002678 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002679{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002680 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002681 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002682 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002683 int err;
2684
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002685 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002686
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002687 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002688 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2689 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002690
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002691 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002692
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002693 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002694 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2695 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002696 goto unlock;
2697 }
2698
2699 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002700 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2701 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002702 goto unlock;
2703 }
2704
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002705 hdev->major_class = cp->major;
2706 hdev->minor_class = cp->minor;
2707
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002708 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002709 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2710 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002711 goto unlock;
2712 }
2713
Johan Hedberg890ea892013-03-15 17:06:52 -05002714 hci_req_init(&req, hdev);
2715
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002716 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002717 hci_dev_unlock(hdev);
2718 cancel_delayed_work_sync(&hdev->service_cache);
2719 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002720 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002721 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002722
Johan Hedberg890ea892013-03-15 17:06:52 -05002723 update_class(&req);
2724
Johan Hedberg92da6092013-03-15 17:06:55 -05002725 err = hci_req_run(&req, set_class_complete);
2726 if (err < 0) {
2727 if (err != -ENODATA)
2728 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002729
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002730 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2731 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002732 goto unlock;
2733 }
2734
2735 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002736 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002737 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002738 goto unlock;
2739 }
2740
2741 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002742
Johan Hedbergb5235a62012-02-21 14:32:24 +02002743unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002744 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002745 return err;
2746}
2747
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002748static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002749 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002750{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002751 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002752 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2753 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002754 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002755 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002756 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002757
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002758 BT_DBG("request for %s", hdev->name);
2759
2760 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002761 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2762 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002763
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002764 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002765 if (key_count > max_key_count) {
2766 BT_ERR("load_link_keys: too big key_count value %u",
2767 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002768 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2769 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002770 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002771
Johan Hedberg86742e12011-11-07 23:13:38 +02002772 expected_len = sizeof(*cp) + key_count *
2773 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002774 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002775 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002776 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002777 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2778 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002779 }
2780
Johan Hedberg4ae14302013-01-20 14:27:13 +02002781 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002782 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2783 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002784
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002785 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002786 key_count);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002787
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002788 for (i = 0; i < key_count; i++) {
2789 struct mgmt_link_key_info *key = &cp->keys[i];
2790
Marcel Holtmann8e991132014-01-10 02:07:25 -08002791 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002792 return mgmt_cmd_status(sk, hdev->id,
2793 MGMT_OP_LOAD_LINK_KEYS,
2794 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002795 }
2796
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002797 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002798
2799 hci_link_keys_clear(hdev);
2800
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002801 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002802 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002803 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002804 changed = hci_dev_test_and_clear_flag(hdev,
2805 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002806
2807 if (changed)
2808 new_settings(hdev, NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002809
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002810 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002811 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002812
Johan Hedberg58e92932014-06-24 14:00:26 +03002813 /* Always ignore debug keys and require a new pairing if
2814 * the user wants to use them.
2815 */
2816 if (key->type == HCI_LK_DEBUG_COMBINATION)
2817 continue;
2818
Johan Hedberg7652ff62014-06-24 13:15:49 +03002819 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2820 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002821 }
2822
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002823 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002824
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002825 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002826
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002827 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002828}
2829
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002830static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002831 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002832{
2833 struct mgmt_ev_device_unpaired ev;
2834
2835 bacpy(&ev.addr.bdaddr, bdaddr);
2836 ev.addr.type = addr_type;
2837
2838 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002839 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002840}
2841
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002842static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002843 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002844{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002845 struct mgmt_cp_unpair_device *cp = data;
2846 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002847 struct hci_cp_disconnect dc;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002848 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002849 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002850 int err;
2851
Johan Hedberga8a1d192011-11-10 15:54:38 +02002852 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002853 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2854 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002855
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002856 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002857 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2858 MGMT_STATUS_INVALID_PARAMS,
2859 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002860
Johan Hedberg118da702013-01-20 14:27:20 +02002861 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002862 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2863 MGMT_STATUS_INVALID_PARAMS,
2864 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002865
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002866 hci_dev_lock(hdev);
2867
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002868 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002869 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2870 MGMT_STATUS_NOT_POWERED, &rp,
2871 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002872 goto unlock;
2873 }
2874
Johan Hedberge0b2b272014-02-18 17:14:31 +02002875 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002876 /* If disconnection is requested, then look up the
2877 * connection. If the remote device is connected, it
2878 * will be later used to terminate the link.
2879 *
2880 * Setting it to NULL explicitly will cause no
2881 * termination of the link.
2882 */
2883 if (cp->disconnect)
2884 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2885 &cp->addr.bdaddr);
2886 else
2887 conn = NULL;
2888
Johan Hedberg124f6e32012-02-09 13:50:12 +02002889 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedberge0b2b272014-02-18 17:14:31 +02002890 } else {
2891 u8 addr_type;
2892
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002893 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
2894 &cp->addr.bdaddr);
2895 if (conn) {
2896 /* Defer clearing up the connection parameters
2897 * until closing to give a chance of keeping
2898 * them if a repairing happens.
2899 */
2900 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2901
2902 /* If disconnection is not requested, then
2903 * clear the connection variable so that the
2904 * link is not terminated.
2905 */
2906 if (!cp->disconnect)
2907 conn = NULL;
2908 }
2909
Johan Hedberge0b2b272014-02-18 17:14:31 +02002910 if (cp->addr.type == BDADDR_LE_PUBLIC)
2911 addr_type = ADDR_LE_DEV_PUBLIC;
2912 else
2913 addr_type = ADDR_LE_DEV_RANDOM;
2914
Johan Hedberga7ec7332014-02-18 17:14:35 +02002915 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2916
Johan Hedberge0b2b272014-02-18 17:14:31 +02002917 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
2918 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002919
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002920 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002921 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2922 MGMT_STATUS_NOT_PAIRED, &rp,
2923 sizeof(rp));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002924 goto unlock;
2925 }
2926
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002927 /* If the connection variable is set, then termination of the
2928 * link is requested.
2929 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002930 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002931 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2932 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002933 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002934 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002935 }
2936
Johan Hedberg124f6e32012-02-09 13:50:12 +02002937 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002938 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002939 if (!cmd) {
2940 err = -ENOMEM;
2941 goto unlock;
2942 }
2943
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002944 cmd->cmd_complete = addr_cmd_complete;
2945
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002946 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002947 dc.reason = 0x13; /* Remote User Terminated Connection */
2948 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2949 if (err < 0)
2950 mgmt_pending_remove(cmd);
2951
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002952unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002953 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002954 return err;
2955}
2956
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002957static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002958 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002959{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002960 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002961 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002962 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002963 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002964 int err;
2965
2966 BT_DBG("");
2967
Johan Hedberg06a63b12013-01-20 14:27:21 +02002968 memset(&rp, 0, sizeof(rp));
2969 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2970 rp.addr.type = cp->addr.type;
2971
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002972 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002973 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2974 MGMT_STATUS_INVALID_PARAMS,
2975 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002976
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002977 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002978
2979 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002980 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2981 MGMT_STATUS_NOT_POWERED, &rp,
2982 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002983 goto failed;
2984 }
2985
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002986 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002987 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2988 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002989 goto failed;
2990 }
2991
Andre Guedes591f47f2012-04-24 21:02:49 -03002992 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002993 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2994 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002995 else
2996 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002997
Vishal Agarwalf9607272012-06-13 05:32:43 +05302998 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002999 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
3000 MGMT_STATUS_NOT_CONNECTED, &rp,
3001 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003002 goto failed;
3003 }
3004
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003005 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03003006 if (!cmd) {
3007 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003008 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03003009 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02003010
Johan Hedbergf5818c22014-12-05 13:36:02 +02003011 cmd->cmd_complete = generic_cmd_complete;
3012
Johan Hedberge3f2f922014-08-18 20:33:33 +03003013 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003014 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03003015 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003016
3017failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003018 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003019 return err;
3020}
3021
Andre Guedes57c14772012-04-24 21:02:50 -03003022static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02003023{
3024 switch (link_type) {
3025 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02003026 switch (addr_type) {
3027 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03003028 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03003029
Johan Hedberg48264f02011-11-09 13:58:58 +02003030 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03003031 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03003032 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02003033 }
Andre Guedes0ed09142012-04-03 08:46:54 -03003034
Johan Hedberg4c659c32011-11-07 23:13:39 +02003035 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03003036 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03003037 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02003038 }
3039}
3040
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003041static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
3042 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02003043{
Johan Hedberg2784eb42011-01-21 13:56:35 +02003044 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02003045 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02003046 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003047 int err;
3048 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02003049
3050 BT_DBG("");
3051
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003052 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003053
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003054 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003055 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
3056 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003057 goto unlock;
3058 }
3059
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003060 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02003061 list_for_each_entry(c, &hdev->conn_hash.list, list) {
3062 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003063 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02003064 }
3065
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003066 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03003067 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02003068 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02003069 err = -ENOMEM;
3070 goto unlock;
3071 }
3072
Johan Hedberg2784eb42011-01-21 13:56:35 +02003073 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02003074 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02003075 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
3076 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02003077 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03003078 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03003079 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02003080 continue;
3081 i++;
3082 }
3083
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003084 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003085
Johan Hedberg4c659c32011-11-07 23:13:39 +02003086 /* Recalculate length in case of filtered SCO connections, etc */
3087 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02003088
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003089 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
3090 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003091
Johan Hedberga38528f2011-01-22 06:46:43 +02003092 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003093
3094unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003095 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003096 return err;
3097}
3098
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003099static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003100 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003101{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003102 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003103 int err;
3104
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003105 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003106 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003107 if (!cmd)
3108 return -ENOMEM;
3109
Johan Hedbergd8457692012-02-17 14:24:57 +02003110 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003111 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003112 if (err < 0)
3113 mgmt_pending_remove(cmd);
3114
3115 return err;
3116}
3117
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003118static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003119 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003120{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003121 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003122 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003123 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003124 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003125 int err;
3126
3127 BT_DBG("");
3128
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003129 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003130
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003131 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003132 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3133 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003134 goto failed;
3135 }
3136
Johan Hedbergd8457692012-02-17 14:24:57 +02003137 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003138 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003139 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3140 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003141 goto failed;
3142 }
3143
3144 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02003145 struct mgmt_cp_pin_code_neg_reply ncp;
3146
3147 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003148
3149 BT_ERR("PIN code is not 16 bytes long");
3150
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003151 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003152 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02003153 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3154 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003155
3156 goto failed;
3157 }
3158
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03003159 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03003160 if (!cmd) {
3161 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003162 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03003163 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02003164
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003165 cmd->cmd_complete = addr_cmd_complete;
3166
Johan Hedbergd8457692012-02-17 14:24:57 +02003167 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003168 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02003169 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003170
3171 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
3172 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03003173 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003174
3175failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003176 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003177 return err;
3178}
3179
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003180static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
3181 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003182{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003183 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003184
3185 BT_DBG("");
3186
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003187 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003188 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
3189 MGMT_STATUS_INVALID_PARAMS, NULL, 0);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003190
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003191 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003192
3193 hdev->io_capability = cp->io_capability;
3194
3195 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003196 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003197
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003198 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003199
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003200 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
3201 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003202}
3203
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003204static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003205{
3206 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003207 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003208
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003209 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03003210 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
3211 continue;
3212
Johan Hedberge9a416b2011-02-19 12:05:56 -03003213 if (cmd->user_data != conn)
3214 continue;
3215
3216 return cmd;
3217 }
3218
3219 return NULL;
3220}
3221
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003222static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003223{
3224 struct mgmt_rp_pair_device rp;
3225 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02003226 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003227
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02003228 bacpy(&rp.addr.bdaddr, &conn->dst);
3229 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003230
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003231 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
3232 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003233
3234 /* So we don't get further callbacks for this connection */
3235 conn->connect_cfm_cb = NULL;
3236 conn->security_cfm_cb = NULL;
3237 conn->disconn_cfm_cb = NULL;
3238
David Herrmann76a68ba2013-04-06 20:28:37 +02003239 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00003240
3241 /* The device is paired so there is no need to remove
3242 * its connection parameters anymore.
3243 */
3244 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02003245
3246 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02003247
3248 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003249}
3250
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003251void mgmt_smp_complete(struct hci_conn *conn, bool complete)
3252{
3253 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003254 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003255
3256 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003257 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02003258 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02003259 mgmt_pending_remove(cmd);
3260 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003261}
3262
Johan Hedberge9a416b2011-02-19 12:05:56 -03003263static void pairing_complete_cb(struct hci_conn *conn, u8 status)
3264{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003265 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003266
3267 BT_DBG("status %u", status);
3268
Johan Hedberg56e5cb82011-11-08 20:40:16 +02003269 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003270 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02003271 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02003272 return;
3273 }
3274
3275 cmd->cmd_complete(cmd, mgmt_status(status));
3276 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003277}
3278
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003279static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303280{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003281 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303282
3283 BT_DBG("status %u", status);
3284
3285 if (!status)
3286 return;
3287
3288 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003289 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303290 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02003291 return;
3292 }
3293
3294 cmd->cmd_complete(cmd, mgmt_status(status));
3295 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303296}
3297
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003298static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003299 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003300{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003301 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02003302 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003303 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003304 u8 sec_level, auth_type;
3305 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003306 int err;
3307
3308 BT_DBG("");
3309
Szymon Jancf950a30e2013-01-18 12:48:07 +01003310 memset(&rp, 0, sizeof(rp));
3311 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3312 rp.addr.type = cp->addr.type;
3313
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003314 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003315 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3316 MGMT_STATUS_INVALID_PARAMS,
3317 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003318
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003319 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003320 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3321 MGMT_STATUS_INVALID_PARAMS,
3322 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003323
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003324 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003325
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003326 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003327 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3328 MGMT_STATUS_NOT_POWERED, &rp,
3329 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003330 goto unlock;
3331 }
3332
Johan Hedberg55e76b32015-03-10 22:34:40 +02003333 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
3334 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3335 MGMT_STATUS_ALREADY_PAIRED, &rp,
3336 sizeof(rp));
3337 goto unlock;
3338 }
3339
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03003340 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02003341 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003342
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003343 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03003344 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
3345 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003346 } else {
3347 u8 addr_type;
3348
3349 /* Convert from L2CAP channel address type to HCI address type
3350 */
3351 if (cp->addr.type == BDADDR_LE_PUBLIC)
3352 addr_type = ADDR_LE_DEV_PUBLIC;
3353 else
3354 addr_type = ADDR_LE_DEV_RANDOM;
3355
Marcel Holtmann7c264b12014-06-30 12:34:40 +02003356 /* When pairing a new device, it is expected to remember
3357 * this device for future connections. Adding the connection
3358 * parameter information ahead of time allows tracking
3359 * of the slave preferred values and will speed up any
3360 * further connection establishment.
3361 *
3362 * If connection parameters already exist, then they
3363 * will be kept and this function does nothing.
3364 */
3365 hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
3366
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003367 conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type,
Johan Hedberge804d252014-07-16 11:42:28 +03003368 sec_level, HCI_LE_CONN_TIMEOUT,
3369 HCI_ROLE_MASTER);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003370 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003371
Ville Tervo30e76272011-02-22 16:10:53 -03003372 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003373 int status;
3374
3375 if (PTR_ERR(conn) == -EBUSY)
3376 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01003377 else if (PTR_ERR(conn) == -EOPNOTSUPP)
3378 status = MGMT_STATUS_NOT_SUPPORTED;
3379 else if (PTR_ERR(conn) == -ECONNREFUSED)
3380 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003381 else
3382 status = MGMT_STATUS_CONNECT_FAILED;
3383
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003384 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3385 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003386 goto unlock;
3387 }
3388
3389 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02003390 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003391 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3392 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003393 goto unlock;
3394 }
3395
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003396 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003397 if (!cmd) {
3398 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02003399 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003400 goto unlock;
3401 }
3402
Johan Hedberg04ab2742014-12-05 13:36:04 +02003403 cmd->cmd_complete = pairing_complete;
3404
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003405 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003406 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003407 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003408 conn->security_cfm_cb = pairing_complete_cb;
3409 conn->disconn_cfm_cb = pairing_complete_cb;
3410 } else {
3411 conn->connect_cfm_cb = le_pairing_complete_cb;
3412 conn->security_cfm_cb = le_pairing_complete_cb;
3413 conn->disconn_cfm_cb = le_pairing_complete_cb;
3414 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003415
Johan Hedberge9a416b2011-02-19 12:05:56 -03003416 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003417 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003418
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003419 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003420 hci_conn_security(conn, sec_level, auth_type, true)) {
3421 cmd->cmd_complete(cmd, 0);
3422 mgmt_pending_remove(cmd);
3423 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003424
3425 err = 0;
3426
3427unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003428 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003429 return err;
3430}
3431
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003432static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3433 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003434{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003435 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003436 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003437 struct hci_conn *conn;
3438 int err;
3439
3440 BT_DBG("");
3441
Johan Hedberg28424702012-02-02 04:02:29 +02003442 hci_dev_lock(hdev);
3443
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003444 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003445 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3446 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003447 goto unlock;
3448 }
3449
Johan Hedberg28424702012-02-02 04:02:29 +02003450 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
3451 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003452 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3453 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003454 goto unlock;
3455 }
3456
3457 conn = cmd->user_data;
3458
3459 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003460 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3461 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003462 goto unlock;
3463 }
3464
Johan Hedberga511b352014-12-11 21:45:45 +02003465 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3466 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003467
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003468 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3469 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003470unlock:
3471 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003472 return err;
3473}
3474
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003475static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003476 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003477 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003478{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003479 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003480 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003481 int err;
3482
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003483 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003484
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003485 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003486 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3487 MGMT_STATUS_NOT_POWERED, addr,
3488 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003489 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003490 }
3491
Johan Hedberg1707c602013-03-15 17:07:15 -05003492 if (addr->type == BDADDR_BREDR)
3493 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003494 else
Johan Hedberg1707c602013-03-15 17:07:15 -05003495 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08003496
Johan Hedberg272d90d2012-02-09 15:26:12 +02003497 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003498 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3499 MGMT_STATUS_NOT_CONNECTED, addr,
3500 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003501 goto done;
3502 }
3503
Johan Hedberg1707c602013-03-15 17:07:15 -05003504 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003505 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003506 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003507 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3508 MGMT_STATUS_SUCCESS, addr,
3509 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003510 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003511 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3512 MGMT_STATUS_FAILED, addr,
3513 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003514
Brian Gix47c15e22011-11-16 13:53:14 -08003515 goto done;
3516 }
3517
Johan Hedberg1707c602013-03-15 17:07:15 -05003518 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003519 if (!cmd) {
3520 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003521 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003522 }
3523
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003524 cmd->cmd_complete = addr_cmd_complete;
3525
Brian Gix0df4c182011-11-16 13:53:13 -08003526 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003527 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3528 struct hci_cp_user_passkey_reply cp;
3529
Johan Hedberg1707c602013-03-15 17:07:15 -05003530 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003531 cp.passkey = passkey;
3532 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3533 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003534 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3535 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003536
Johan Hedberga664b5b2011-02-19 12:06:02 -03003537 if (err < 0)
3538 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003539
Brian Gix0df4c182011-11-16 13:53:13 -08003540done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003541 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003542 return err;
3543}
3544
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303545static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3546 void *data, u16 len)
3547{
3548 struct mgmt_cp_pin_code_neg_reply *cp = data;
3549
3550 BT_DBG("");
3551
Johan Hedberg1707c602013-03-15 17:07:15 -05003552 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303553 MGMT_OP_PIN_CODE_NEG_REPLY,
3554 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3555}
3556
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003557static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3558 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003559{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003560 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003561
3562 BT_DBG("");
3563
3564 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003565 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3566 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003567
Johan Hedberg1707c602013-03-15 17:07:15 -05003568 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003569 MGMT_OP_USER_CONFIRM_REPLY,
3570 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003571}
3572
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003573static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003574 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003575{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003576 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003577
3578 BT_DBG("");
3579
Johan Hedberg1707c602013-03-15 17:07:15 -05003580 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003581 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3582 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003583}
3584
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003585static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3586 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003587{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003588 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003589
3590 BT_DBG("");
3591
Johan Hedberg1707c602013-03-15 17:07:15 -05003592 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003593 MGMT_OP_USER_PASSKEY_REPLY,
3594 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003595}
3596
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003597static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003598 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003599{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003600 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003601
3602 BT_DBG("");
3603
Johan Hedberg1707c602013-03-15 17:07:15 -05003604 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003605 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3606 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003607}
3608
Johan Hedberg13928972013-03-15 17:07:00 -05003609static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003610{
Johan Hedberg13928972013-03-15 17:07:00 -05003611 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003612 struct hci_cp_write_local_name cp;
3613
Johan Hedberg13928972013-03-15 17:07:00 -05003614 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003615
Johan Hedberg890ea892013-03-15 17:06:52 -05003616 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003617}
3618
Marcel Holtmann1904a852015-01-11 13:50:44 -08003619static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003620{
3621 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003622 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003623
3624 BT_DBG("status 0x%02x", status);
3625
3626 hci_dev_lock(hdev);
3627
3628 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
3629 if (!cmd)
3630 goto unlock;
3631
3632 cp = cmd->param;
3633
3634 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003635 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3636 mgmt_status(status));
Johan Hedberg13928972013-03-15 17:07:00 -05003637 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003638 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3639 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003640
3641 mgmt_pending_remove(cmd);
3642
3643unlock:
3644 hci_dev_unlock(hdev);
3645}
3646
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003647static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003648 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003649{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003650 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003651 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003652 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003653 int err;
3654
3655 BT_DBG("");
3656
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003657 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003658
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003659 /* If the old values are the same as the new ones just return a
3660 * direct command complete event.
3661 */
3662 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3663 !memcmp(hdev->short_name, cp->short_name,
3664 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003665 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3666 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003667 goto failed;
3668 }
3669
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003670 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003671
Johan Hedbergb5235a62012-02-21 14:32:24 +02003672 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003673 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003674
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003675 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3676 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003677 if (err < 0)
3678 goto failed;
3679
3680 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003681 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003682
Johan Hedbergb5235a62012-02-21 14:32:24 +02003683 goto failed;
3684 }
3685
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003686 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003687 if (!cmd) {
3688 err = -ENOMEM;
3689 goto failed;
3690 }
3691
Johan Hedberg13928972013-03-15 17:07:00 -05003692 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3693
Johan Hedberg890ea892013-03-15 17:06:52 -05003694 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003695
3696 if (lmp_bredr_capable(hdev)) {
3697 update_name(&req);
3698 update_eir(&req);
3699 }
3700
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003701 /* The name is stored in the scan response data and so
3702 * no need to udpate the advertising data here.
3703 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003704 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003705 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003706
Johan Hedberg13928972013-03-15 17:07:00 -05003707 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003708 if (err < 0)
3709 mgmt_pending_remove(cmd);
3710
3711failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003712 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003713 return err;
3714}
3715
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003716static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003717 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003718{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003719 struct mgmt_pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01003720 int err;
3721
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003722 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003723
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003724 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003725
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003726 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003727 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3728 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003729 goto unlock;
3730 }
3731
Andre Guedes9a1a1992012-07-24 15:03:48 -03003732 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003733 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3734 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003735 goto unlock;
3736 }
3737
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003738 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003739 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3740 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003741 goto unlock;
3742 }
3743
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003744 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003745 if (!cmd) {
3746 err = -ENOMEM;
3747 goto unlock;
3748 }
3749
Johan Hedberg710f11c2014-05-26 11:21:22 +03003750 if (bredr_sc_enabled(hdev))
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003751 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
3752 0, NULL);
3753 else
3754 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3755
Szymon Jancc35938b2011-03-22 13:12:21 +01003756 if (err < 0)
3757 mgmt_pending_remove(cmd);
3758
3759unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003760 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003761 return err;
3762}
3763
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003764static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003765 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003766{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003767 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003768 int err;
3769
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003770 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003771
Johan Hedberg5d57e792015-01-23 10:10:38 +02003772 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003773 return mgmt_cmd_complete(sk, hdev->id,
3774 MGMT_OP_ADD_REMOTE_OOB_DATA,
3775 MGMT_STATUS_INVALID_PARAMS,
3776 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003777
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003778 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003779
Marcel Holtmannec109112014-01-10 02:07:30 -08003780 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3781 struct mgmt_cp_add_remote_oob_data *cp = data;
3782 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003783
Johan Hedbergc19a4952014-11-17 20:52:19 +02003784 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003785 err = mgmt_cmd_complete(sk, hdev->id,
3786 MGMT_OP_ADD_REMOTE_OOB_DATA,
3787 MGMT_STATUS_INVALID_PARAMS,
3788 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003789 goto unlock;
3790 }
3791
Marcel Holtmannec109112014-01-10 02:07:30 -08003792 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003793 cp->addr.type, cp->hash,
3794 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003795 if (err < 0)
3796 status = MGMT_STATUS_FAILED;
3797 else
3798 status = MGMT_STATUS_SUCCESS;
3799
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003800 err = mgmt_cmd_complete(sk, hdev->id,
3801 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3802 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003803 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3804 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003805 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003806 u8 status;
3807
Johan Hedberg86df9202014-10-26 20:52:27 +01003808 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003809 /* Enforce zero-valued 192-bit parameters as
3810 * long as legacy SMP OOB isn't implemented.
3811 */
3812 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3813 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003814 err = mgmt_cmd_complete(sk, hdev->id,
3815 MGMT_OP_ADD_REMOTE_OOB_DATA,
3816 MGMT_STATUS_INVALID_PARAMS,
3817 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003818 goto unlock;
3819 }
3820
Johan Hedberg86df9202014-10-26 20:52:27 +01003821 rand192 = NULL;
3822 hash192 = NULL;
3823 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003824 /* In case one of the P-192 values is set to zero,
3825 * then just disable OOB data for P-192.
3826 */
3827 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3828 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3829 rand192 = NULL;
3830 hash192 = NULL;
3831 } else {
3832 rand192 = cp->rand192;
3833 hash192 = cp->hash192;
3834 }
3835 }
3836
3837 /* In case one of the P-256 values is set to zero, then just
3838 * disable OOB data for P-256.
3839 */
3840 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3841 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3842 rand256 = NULL;
3843 hash256 = NULL;
3844 } else {
3845 rand256 = cp->rand256;
3846 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003847 }
3848
Johan Hedberg81328d52014-10-26 20:33:47 +01003849 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003850 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003851 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003852 if (err < 0)
3853 status = MGMT_STATUS_FAILED;
3854 else
3855 status = MGMT_STATUS_SUCCESS;
3856
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003857 err = mgmt_cmd_complete(sk, hdev->id,
3858 MGMT_OP_ADD_REMOTE_OOB_DATA,
3859 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003860 } else {
3861 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003862 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3863 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003864 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003865
Johan Hedbergc19a4952014-11-17 20:52:19 +02003866unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003867 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003868 return err;
3869}
3870
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003871static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003872 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003873{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003874 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003875 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003876 int err;
3877
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003878 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003879
Johan Hedbergc19a4952014-11-17 20:52:19 +02003880 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003881 return mgmt_cmd_complete(sk, hdev->id,
3882 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3883 MGMT_STATUS_INVALID_PARAMS,
3884 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003885
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003886 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003887
Johan Hedbergeedbd582014-11-15 09:34:23 +02003888 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3889 hci_remote_oob_data_clear(hdev);
3890 status = MGMT_STATUS_SUCCESS;
3891 goto done;
3892 }
3893
Johan Hedberg6928a922014-10-26 20:46:09 +01003894 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003895 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003896 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003897 else
Szymon Janca6785be2012-12-13 15:11:21 +01003898 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003899
Johan Hedbergeedbd582014-11-15 09:34:23 +02003900done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003901 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3902 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003903
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003904 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003905 return err;
3906}
3907
Marcel Holtmann80190442014-12-04 11:36:36 +01003908static bool trigger_discovery(struct hci_request *req, u8 *status)
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003909{
Marcel Holtmann80190442014-12-04 11:36:36 +01003910 struct hci_dev *hdev = req->hdev;
3911 struct hci_cp_le_set_scan_param param_cp;
3912 struct hci_cp_le_set_scan_enable enable_cp;
3913 struct hci_cp_inquiry inq_cp;
3914 /* General inquiry access code (GIAC) */
3915 u8 lap[3] = { 0x33, 0x8b, 0x9e };
3916 u8 own_addr_type;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003917 int err;
3918
Marcel Holtmann80190442014-12-04 11:36:36 +01003919 switch (hdev->discovery.type) {
3920 case DISCOV_TYPE_BREDR:
3921 *status = mgmt_bredr_support(hdev);
3922 if (*status)
3923 return false;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003924
Marcel Holtmann80190442014-12-04 11:36:36 +01003925 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3926 *status = MGMT_STATUS_BUSY;
3927 return false;
3928 }
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003929
Marcel Holtmann80190442014-12-04 11:36:36 +01003930 hci_inquiry_cache_flush(hdev);
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003931
Marcel Holtmann80190442014-12-04 11:36:36 +01003932 memset(&inq_cp, 0, sizeof(inq_cp));
3933 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
3934 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
3935 hci_req_add(req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
3936 break;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003937
Marcel Holtmann80190442014-12-04 11:36:36 +01003938 case DISCOV_TYPE_LE:
3939 case DISCOV_TYPE_INTERLEAVED:
3940 *status = mgmt_le_support(hdev);
3941 if (*status)
3942 return false;
3943
3944 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003945 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmann80190442014-12-04 11:36:36 +01003946 *status = MGMT_STATUS_NOT_SUPPORTED;
3947 return false;
3948 }
3949
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003950 if (hci_dev_test_flag(hdev, HCI_LE_ADV)) {
Marcel Holtmann80190442014-12-04 11:36:36 +01003951 /* Don't let discovery abort an outgoing
3952 * connection attempt that's using directed
3953 * advertising.
3954 */
3955 if (hci_conn_hash_lookup_state(hdev, LE_LINK,
3956 BT_CONNECT)) {
3957 *status = MGMT_STATUS_REJECTED;
3958 return false;
3959 }
3960
3961 disable_advertising(req);
3962 }
3963
3964 /* If controller is scanning, it means the background scanning
3965 * is running. Thus, we should temporarily stop it in order to
3966 * set the discovery scanning parameters.
3967 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003968 if (hci_dev_test_flag(hdev, HCI_LE_SCAN))
Marcel Holtmann80190442014-12-04 11:36:36 +01003969 hci_req_add_le_scan_disable(req);
3970
3971 memset(&param_cp, 0, sizeof(param_cp));
3972
3973 /* All active scans will be done with either a resolvable
3974 * private address (when privacy feature has been enabled)
Marcel Holtmann9437d2e2014-12-07 20:13:17 +01003975 * or non-resolvable private address.
Marcel Holtmann80190442014-12-04 11:36:36 +01003976 */
3977 err = hci_update_random_address(req, true, &own_addr_type);
3978 if (err < 0) {
3979 *status = MGMT_STATUS_FAILED;
3980 return false;
3981 }
3982
3983 param_cp.type = LE_SCAN_ACTIVE;
3984 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3985 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
3986 param_cp.own_address_type = own_addr_type;
3987 hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3988 &param_cp);
3989
3990 memset(&enable_cp, 0, sizeof(enable_cp));
3991 enable_cp.enable = LE_SCAN_ENABLE;
3992 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3993 hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3994 &enable_cp);
3995 break;
3996
3997 default:
3998 *status = MGMT_STATUS_INVALID_PARAMS;
3999 return false;
4000 }
4001
4002 return true;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03004003}
4004
Marcel Holtmann1904a852015-01-11 13:50:44 -08004005static void start_discovery_complete(struct hci_dev *hdev, u8 status,
4006 u16 opcode)
Andre Guedes7c307722013-04-30 15:29:28 -03004007{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004008 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004009 unsigned long timeout;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004010
Andre Guedes7c307722013-04-30 15:29:28 -03004011 BT_DBG("status %d", status);
4012
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004013 hci_dev_lock(hdev);
4014
4015 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004016 if (!cmd)
4017 cmd = mgmt_pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
4018
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004019 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004020 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004021 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03004022 }
4023
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004024 if (status) {
4025 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
4026 goto unlock;
4027 }
4028
Andre Guedes7c307722013-04-30 15:29:28 -03004029 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
Andre Guedes7c307722013-04-30 15:29:28 -03004030
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004031 /* If the scan involves LE scan, pick proper timeout to schedule
4032 * hdev->le_scan_disable that will stop it.
4033 */
Andre Guedes7c307722013-04-30 15:29:28 -03004034 switch (hdev->discovery.type) {
4035 case DISCOV_TYPE_LE:
Lukasz Rymanowski3d5a76f2014-03-27 20:55:21 +01004036 timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03004037 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004038 case DISCOV_TYPE_INTERLEAVED:
Lukasz Rymanowskib9a7a612014-03-27 20:55:20 +01004039 timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
Andre Guedes7c307722013-04-30 15:29:28 -03004040 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004041 case DISCOV_TYPE_BREDR:
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004042 timeout = 0;
Andre Guedes7c307722013-04-30 15:29:28 -03004043 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004044 default:
4045 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004046 timeout = 0;
4047 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004048 }
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004049
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004050 if (timeout) {
4051 /* When service discovery is used and the controller has
4052 * a strict duplicate filter, it is important to remember
4053 * the start and duration of the scan. This is required
4054 * for restarting scanning during the discovery phase.
4055 */
4056 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER,
4057 &hdev->quirks) &&
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004058 hdev->discovery.result_filtering) {
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004059 hdev->discovery.scan_start = jiffies;
4060 hdev->discovery.scan_duration = timeout;
4061 }
4062
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004063 queue_delayed_work(hdev->workqueue,
4064 &hdev->le_scan_disable, timeout);
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004065 }
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004066
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004067unlock:
4068 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03004069}
4070
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004071static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004072 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004073{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004074 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004075 struct mgmt_pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03004076 struct hci_request req;
Marcel Holtmann80190442014-12-04 11:36:36 +01004077 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04004078 int err;
4079
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004080 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004081
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004082 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004083
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004084 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004085 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4086 MGMT_STATUS_NOT_POWERED,
4087 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02004088 goto failed;
4089 }
4090
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004091 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004092 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004093 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4094 MGMT_STATUS_BUSY, &cp->type,
4095 sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03004096 goto failed;
4097 }
4098
Johan Hedberg2922a942014-12-05 13:36:06 +02004099 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004100 if (!cmd) {
4101 err = -ENOMEM;
4102 goto failed;
4103 }
4104
Johan Hedberg2922a942014-12-05 13:36:06 +02004105 cmd->cmd_complete = generic_cmd_complete;
4106
Marcel Holtmann22078802014-12-05 11:45:22 +01004107 /* Clear the discovery filter first to free any previously
4108 * allocated memory for the UUID list.
4109 */
4110 hci_discovery_filter_clear(hdev);
4111
Andre Guedes4aab14e2012-02-17 20:39:36 -03004112 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01004113 hdev->discovery.report_invalid_rssi = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03004114
Andre Guedes7c307722013-04-30 15:29:28 -03004115 hci_req_init(&req, hdev);
4116
Marcel Holtmann80190442014-12-04 11:36:36 +01004117 if (!trigger_discovery(&req, &status)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004118 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4119 status, &cp->type, sizeof(cp->type));
Johan Hedberg04106752013-01-10 14:54:09 +02004120 mgmt_pending_remove(cmd);
4121 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004122 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004123
Andre Guedes7c307722013-04-30 15:29:28 -03004124 err = hci_req_run(&req, start_discovery_complete);
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004125 if (err < 0) {
Johan Hedberg14a53662011-04-27 10:29:56 -04004126 mgmt_pending_remove(cmd);
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004127 goto failed;
4128 }
4129
4130 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04004131
4132failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004133 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004134 return err;
4135}
4136
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004137static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4138 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004139{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004140 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4141 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004142}
4143
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004144static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4145 void *data, u16 len)
4146{
4147 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004148 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004149 struct hci_request req;
4150 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4151 u16 uuid_count, expected_len;
4152 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004153 int err;
4154
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004155 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004156
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004157 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004158
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004159 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004160 err = mgmt_cmd_complete(sk, hdev->id,
4161 MGMT_OP_START_SERVICE_DISCOVERY,
4162 MGMT_STATUS_NOT_POWERED,
4163 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004164 goto failed;
4165 }
4166
4167 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004168 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004169 err = mgmt_cmd_complete(sk, hdev->id,
4170 MGMT_OP_START_SERVICE_DISCOVERY,
4171 MGMT_STATUS_BUSY, &cp->type,
4172 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004173 goto failed;
4174 }
4175
4176 uuid_count = __le16_to_cpu(cp->uuid_count);
4177 if (uuid_count > max_uuid_count) {
4178 BT_ERR("service_discovery: too big uuid_count value %u",
4179 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004180 err = mgmt_cmd_complete(sk, hdev->id,
4181 MGMT_OP_START_SERVICE_DISCOVERY,
4182 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4183 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004184 goto failed;
4185 }
4186
4187 expected_len = sizeof(*cp) + uuid_count * 16;
4188 if (expected_len != len) {
4189 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
4190 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004191 err = mgmt_cmd_complete(sk, hdev->id,
4192 MGMT_OP_START_SERVICE_DISCOVERY,
4193 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4194 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004195 goto failed;
4196 }
4197
4198 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02004199 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004200 if (!cmd) {
4201 err = -ENOMEM;
4202 goto failed;
4203 }
4204
Johan Hedberg2922a942014-12-05 13:36:06 +02004205 cmd->cmd_complete = service_discovery_cmd_complete;
4206
Marcel Holtmann22078802014-12-05 11:45:22 +01004207 /* Clear the discovery filter first to free any previously
4208 * allocated memory for the UUID list.
4209 */
4210 hci_discovery_filter_clear(hdev);
4211
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004212 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004213 hdev->discovery.type = cp->type;
4214 hdev->discovery.rssi = cp->rssi;
4215 hdev->discovery.uuid_count = uuid_count;
4216
4217 if (uuid_count > 0) {
4218 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4219 GFP_KERNEL);
4220 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004221 err = mgmt_cmd_complete(sk, hdev->id,
4222 MGMT_OP_START_SERVICE_DISCOVERY,
4223 MGMT_STATUS_FAILED,
4224 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004225 mgmt_pending_remove(cmd);
4226 goto failed;
4227 }
4228 }
4229
4230 hci_req_init(&req, hdev);
4231
4232 if (!trigger_discovery(&req, &status)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004233 err = mgmt_cmd_complete(sk, hdev->id,
4234 MGMT_OP_START_SERVICE_DISCOVERY,
4235 status, &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004236 mgmt_pending_remove(cmd);
4237 goto failed;
4238 }
4239
4240 err = hci_req_run(&req, start_discovery_complete);
4241 if (err < 0) {
4242 mgmt_pending_remove(cmd);
4243 goto failed;
4244 }
4245
4246 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
4247
4248failed:
4249 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004250 return err;
4251}
4252
Marcel Holtmann1904a852015-01-11 13:50:44 -08004253static void stop_discovery_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004254{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004255 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004256
Andre Guedes0e05bba2013-04-30 15:29:33 -03004257 BT_DBG("status %d", status);
4258
4259 hci_dev_lock(hdev);
4260
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004261 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
4262 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004263 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004264 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004265 }
4266
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004267 if (!status)
4268 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004269
Andre Guedes0e05bba2013-04-30 15:29:33 -03004270 hci_dev_unlock(hdev);
4271}
4272
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004273static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004274 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004275{
Johan Hedbergd9306502012-02-20 23:25:18 +02004276 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004277 struct mgmt_pending_cmd *cmd;
Andre Guedes0e05bba2013-04-30 15:29:33 -03004278 struct hci_request req;
Johan Hedberg14a53662011-04-27 10:29:56 -04004279 int err;
4280
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004281 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004282
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004283 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004284
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004285 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004286 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4287 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4288 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004289 goto unlock;
4290 }
4291
4292 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004293 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4294 MGMT_STATUS_INVALID_PARAMS,
4295 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004296 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004297 }
4298
Johan Hedberg2922a942014-12-05 13:36:06 +02004299 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004300 if (!cmd) {
4301 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004302 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004303 }
4304
Johan Hedberg2922a942014-12-05 13:36:06 +02004305 cmd->cmd_complete = generic_cmd_complete;
4306
Andre Guedes0e05bba2013-04-30 15:29:33 -03004307 hci_req_init(&req, hdev);
4308
Johan Hedberg21a60d32014-06-10 14:05:58 +03004309 hci_stop_discovery(&req);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004310
Johan Hedberg21a60d32014-06-10 14:05:58 +03004311 err = hci_req_run(&req, stop_discovery_complete);
4312 if (!err) {
4313 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004314 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004315 }
4316
Johan Hedberg21a60d32014-06-10 14:05:58 +03004317 mgmt_pending_remove(cmd);
4318
4319 /* If no HCI commands were sent we're done */
4320 if (err == -ENODATA) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004321 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
4322 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg21a60d32014-06-10 14:05:58 +03004323 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
4324 }
Johan Hedberg14a53662011-04-27 10:29:56 -04004325
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004326unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004327 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004328 return err;
4329}
4330
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004331static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004332 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004333{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004334 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004335 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004336 int err;
4337
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004338 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004339
Johan Hedberg561aafb2012-01-04 13:31:59 +02004340 hci_dev_lock(hdev);
4341
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004342 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004343 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4344 MGMT_STATUS_FAILED, &cp->addr,
4345 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004346 goto failed;
4347 }
4348
Johan Hedberga198e7b2012-02-17 14:27:06 +02004349 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004350 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004351 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4352 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4353 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004354 goto failed;
4355 }
4356
4357 if (cp->name_known) {
4358 e->name_state = NAME_KNOWN;
4359 list_del(&e->list);
4360 } else {
4361 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02004362 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004363 }
4364
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004365 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4366 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004367
4368failed:
4369 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004370 return err;
4371}
4372
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004373static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004374 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004375{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004376 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004377 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004378 int err;
4379
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004380 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004381
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004382 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004383 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4384 MGMT_STATUS_INVALID_PARAMS,
4385 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004386
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004387 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004388
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004389 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4390 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004391 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004392 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004393 goto done;
4394 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004395
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004396 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4397 sk);
4398 status = MGMT_STATUS_SUCCESS;
4399
4400done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004401 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4402 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004403
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004404 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004405
4406 return err;
4407}
4408
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004409static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004410 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004411{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004412 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004413 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004414 int err;
4415
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004416 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004417
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004418 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004419 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4420 MGMT_STATUS_INVALID_PARAMS,
4421 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004422
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004423 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004424
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004425 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4426 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004427 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004428 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004429 goto done;
4430 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004431
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004432 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4433 sk);
4434 status = MGMT_STATUS_SUCCESS;
4435
4436done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004437 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4438 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004439
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004440 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004441
4442 return err;
4443}
4444
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004445static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4446 u16 len)
4447{
4448 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004449 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004450 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004451 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004452
4453 BT_DBG("%s", hdev->name);
4454
Szymon Jancc72d4b82012-03-16 16:02:57 +01004455 source = __le16_to_cpu(cp->source);
4456
4457 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004458 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4459 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004460
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004461 hci_dev_lock(hdev);
4462
Szymon Jancc72d4b82012-03-16 16:02:57 +01004463 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004464 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4465 hdev->devid_product = __le16_to_cpu(cp->product);
4466 hdev->devid_version = __le16_to_cpu(cp->version);
4467
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004468 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4469 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004470
Johan Hedberg890ea892013-03-15 17:06:52 -05004471 hci_req_init(&req, hdev);
4472 update_eir(&req);
4473 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004474
4475 hci_dev_unlock(hdev);
4476
4477 return err;
4478}
4479
Marcel Holtmann1904a852015-01-11 13:50:44 -08004480static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4481 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004482{
4483 struct cmd_lookup match = { NULL, hdev };
4484
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304485 hci_dev_lock(hdev);
4486
Johan Hedberg4375f102013-09-25 13:26:10 +03004487 if (status) {
4488 u8 mgmt_err = mgmt_status(status);
4489
4490 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4491 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304492 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004493 }
4494
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004495 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004496 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004497 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004498 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004499
Johan Hedberg4375f102013-09-25 13:26:10 +03004500 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4501 &match);
4502
4503 new_settings(hdev, match.sk);
4504
4505 if (match.sk)
4506 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304507
4508unlock:
4509 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004510}
4511
Marcel Holtmann21b51872013-10-10 09:47:53 -07004512static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4513 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004514{
4515 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004516 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004517 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004518 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004519 int err;
4520
4521 BT_DBG("request for %s", hdev->name);
4522
Johan Hedberge6fe7982013-10-02 15:45:22 +03004523 status = mgmt_le_support(hdev);
4524 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004525 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4526 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004527
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004528 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004529 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4530 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004531
4532 hci_dev_lock(hdev);
4533
4534 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004535
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004536 /* The following conditions are ones which mean that we should
4537 * not do any HCI communication but directly send a mgmt
4538 * response to user space (after toggling the flag if
4539 * necessary).
4540 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004541 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004542 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4543 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004544 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004545 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004546 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004547 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004548
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004549 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004550 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004551 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004552 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004553 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004554 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004555 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004556 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004557 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004558 }
4559
4560 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4561 if (err < 0)
4562 goto unlock;
4563
4564 if (changed)
4565 err = new_settings(hdev, sk);
4566
4567 goto unlock;
4568 }
4569
4570 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4571 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004572 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4573 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004574 goto unlock;
4575 }
4576
4577 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4578 if (!cmd) {
4579 err = -ENOMEM;
4580 goto unlock;
4581 }
4582
4583 hci_req_init(&req, hdev);
4584
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004585 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004586 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004587 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004588 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004589
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004590 if (val)
4591 enable_advertising(&req);
4592 else
4593 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03004594
4595 err = hci_req_run(&req, set_advertising_complete);
4596 if (err < 0)
4597 mgmt_pending_remove(cmd);
4598
4599unlock:
4600 hci_dev_unlock(hdev);
4601 return err;
4602}
4603
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004604static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4605 void *data, u16 len)
4606{
4607 struct mgmt_cp_set_static_address *cp = data;
4608 int err;
4609
4610 BT_DBG("%s", hdev->name);
4611
Marcel Holtmann62af4442013-10-02 22:10:32 -07004612 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004613 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4614 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004615
4616 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004617 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4618 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004619
4620 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4621 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004622 return mgmt_cmd_status(sk, hdev->id,
4623 MGMT_OP_SET_STATIC_ADDRESS,
4624 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004625
4626 /* Two most significant bits shall be set */
4627 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004628 return mgmt_cmd_status(sk, hdev->id,
4629 MGMT_OP_SET_STATIC_ADDRESS,
4630 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004631 }
4632
4633 hci_dev_lock(hdev);
4634
4635 bacpy(&hdev->static_addr, &cp->bdaddr);
4636
Marcel Holtmann93690c22015-03-06 10:11:21 -08004637 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4638 if (err < 0)
4639 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004640
Marcel Holtmann93690c22015-03-06 10:11:21 -08004641 err = new_settings(hdev, sk);
4642
4643unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004644 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004645 return err;
4646}
4647
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004648static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4649 void *data, u16 len)
4650{
4651 struct mgmt_cp_set_scan_params *cp = data;
4652 __u16 interval, window;
4653 int err;
4654
4655 BT_DBG("%s", hdev->name);
4656
4657 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004658 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4659 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004660
4661 interval = __le16_to_cpu(cp->interval);
4662
4663 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004664 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4665 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004666
4667 window = __le16_to_cpu(cp->window);
4668
4669 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004670 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4671 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004672
Marcel Holtmann899e1072013-10-14 09:55:32 -07004673 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004674 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4675 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004676
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004677 hci_dev_lock(hdev);
4678
4679 hdev->le_scan_interval = interval;
4680 hdev->le_scan_window = window;
4681
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004682 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4683 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004684
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004685 /* If background scan is running, restart it so new parameters are
4686 * loaded.
4687 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004688 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004689 hdev->discovery.state == DISCOVERY_STOPPED) {
4690 struct hci_request req;
4691
4692 hci_req_init(&req, hdev);
4693
4694 hci_req_add_le_scan_disable(&req);
4695 hci_req_add_le_passive_scan(&req);
4696
4697 hci_req_run(&req, NULL);
4698 }
4699
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004700 hci_dev_unlock(hdev);
4701
4702 return err;
4703}
4704
Marcel Holtmann1904a852015-01-11 13:50:44 -08004705static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4706 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004707{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004708 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004709
4710 BT_DBG("status 0x%02x", status);
4711
4712 hci_dev_lock(hdev);
4713
4714 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4715 if (!cmd)
4716 goto unlock;
4717
4718 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004719 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4720 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004721 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004722 struct mgmt_mode *cp = cmd->param;
4723
4724 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004725 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004726 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004727 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004728
Johan Hedberg33e38b32013-03-15 17:07:05 -05004729 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4730 new_settings(hdev, cmd->sk);
4731 }
4732
4733 mgmt_pending_remove(cmd);
4734
4735unlock:
4736 hci_dev_unlock(hdev);
4737}
4738
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004739static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004740 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004741{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004742 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004743 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004744 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004745 int err;
4746
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004747 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004748
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004749 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004750 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004751 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4752 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004753
Johan Hedberga7e80f22013-01-09 16:05:19 +02004754 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004755 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4756 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004757
Antti Julkuf6422ec2011-06-22 13:11:56 +03004758 hci_dev_lock(hdev);
4759
Johan Hedberg05cbf292013-03-15 17:07:07 -05004760 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004761 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4762 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004763 goto unlock;
4764 }
4765
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004766 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004767 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4768 hdev);
4769 goto unlock;
4770 }
4771
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004772 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004773 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004774 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4775 hdev);
4776 new_settings(hdev, sk);
4777 goto unlock;
4778 }
4779
Johan Hedberg33e38b32013-03-15 17:07:05 -05004780 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4781 data, len);
4782 if (!cmd) {
4783 err = -ENOMEM;
4784 goto unlock;
4785 }
4786
4787 hci_req_init(&req, hdev);
4788
Johan Hedberg406d7802013-03-15 17:07:09 -05004789 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004790
4791 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004792 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004793 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4794 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004795 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004796 }
4797
Johan Hedberg33e38b32013-03-15 17:07:05 -05004798unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004799 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004800
Antti Julkuf6422ec2011-06-22 13:11:56 +03004801 return err;
4802}
4803
Marcel Holtmann1904a852015-01-11 13:50:44 -08004804static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004805{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004806 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004807
4808 BT_DBG("status 0x%02x", status);
4809
4810 hci_dev_lock(hdev);
4811
4812 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
4813 if (!cmd)
4814 goto unlock;
4815
4816 if (status) {
4817 u8 mgmt_err = mgmt_status(status);
4818
4819 /* We need to restore the flag if related HCI commands
4820 * failed.
4821 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004822 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004823
Johan Hedberga69e8372015-03-06 21:08:53 +02004824 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004825 } else {
4826 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4827 new_settings(hdev, cmd->sk);
4828 }
4829
4830 mgmt_pending_remove(cmd);
4831
4832unlock:
4833 hci_dev_unlock(hdev);
4834}
4835
4836static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4837{
4838 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004839 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004840 struct hci_request req;
4841 int err;
4842
4843 BT_DBG("request for %s", hdev->name);
4844
4845 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004846 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4847 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004848
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004849 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004850 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4851 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004852
4853 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004854 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4855 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004856
4857 hci_dev_lock(hdev);
4858
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004859 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004860 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4861 goto unlock;
4862 }
4863
4864 if (!hdev_is_powered(hdev)) {
4865 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004866 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4867 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4868 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4869 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4870 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004871 }
4872
Marcel Holtmannce05d602015-03-13 02:11:03 -07004873 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004874
4875 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4876 if (err < 0)
4877 goto unlock;
4878
4879 err = new_settings(hdev, sk);
4880 goto unlock;
4881 }
4882
4883 /* Reject disabling when powered on */
4884 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004885 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4886 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004887 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004888 } else {
4889 /* When configuring a dual-mode controller to operate
4890 * with LE only and using a static address, then switching
4891 * BR/EDR back on is not allowed.
4892 *
4893 * Dual-mode controllers shall operate with the public
4894 * address as its identity address for BR/EDR and LE. So
4895 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004896 *
4897 * The same restrictions applies when secure connections
4898 * has been enabled. For BR/EDR this is a controller feature
4899 * while for LE it is a host stack feature. This means that
4900 * switching BR/EDR back on when secure connections has been
4901 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004902 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004903 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004904 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004905 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004906 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4907 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004908 goto unlock;
4909 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004910 }
4911
4912 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004913 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4914 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004915 goto unlock;
4916 }
4917
4918 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4919 if (!cmd) {
4920 err = -ENOMEM;
4921 goto unlock;
4922 }
4923
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004924 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03004925 * generates the correct flags.
4926 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004927 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004928
4929 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004930
Johan Hedberg432df052014-08-01 11:13:31 +03004931 write_fast_connectable(&req, false);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02004932 __hci_update_page_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004933
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004934 /* Since only the advertising data flags will change, there
4935 * is no need to update the scan response data.
4936 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004937 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004938
Johan Hedberg0663ca22013-10-02 13:43:14 +03004939 err = hci_req_run(&req, set_bredr_complete);
4940 if (err < 0)
4941 mgmt_pending_remove(cmd);
4942
4943unlock:
4944 hci_dev_unlock(hdev);
4945 return err;
4946}
4947
Johan Hedberga1443f52015-01-23 15:42:46 +02004948static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4949{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004950 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004951 struct mgmt_mode *cp;
4952
4953 BT_DBG("%s status %u", hdev->name, status);
4954
4955 hci_dev_lock(hdev);
4956
4957 cmd = mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
4958 if (!cmd)
4959 goto unlock;
4960
4961 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004962 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4963 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004964 goto remove;
4965 }
4966
4967 cp = cmd->param;
4968
4969 switch (cp->val) {
4970 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004971 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4972 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004973 break;
4974 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004975 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004976 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004977 break;
4978 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004979 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4980 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004981 break;
4982 }
4983
4984 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
4985 new_settings(hdev, cmd->sk);
4986
4987remove:
4988 mgmt_pending_remove(cmd);
4989unlock:
4990 hci_dev_unlock(hdev);
4991}
4992
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004993static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4994 void *data, u16 len)
4995{
4996 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004997 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004998 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03004999 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005000 int err;
5001
5002 BT_DBG("request for %s", hdev->name);
5003
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005004 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005005 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005006 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5007 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005008
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005009 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02005010 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005011 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005012 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5013 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08005014
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005015 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005016 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005017 MGMT_STATUS_INVALID_PARAMS);
5018
5019 hci_dev_lock(hdev);
5020
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005021 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005022 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005023 bool changed;
5024
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005025 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005026 changed = !hci_dev_test_and_set_flag(hdev,
5027 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005028 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005029 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005030 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005031 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005032 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005033 changed = hci_dev_test_and_clear_flag(hdev,
5034 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005035 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005036 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005037
5038 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5039 if (err < 0)
5040 goto failed;
5041
5042 if (changed)
5043 err = new_settings(hdev, sk);
5044
5045 goto failed;
5046 }
5047
5048 if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005049 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5050 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005051 goto failed;
5052 }
5053
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005054 val = !!cp->val;
5055
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005056 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5057 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005058 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5059 goto failed;
5060 }
5061
5062 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
5063 if (!cmd) {
5064 err = -ENOMEM;
5065 goto failed;
5066 }
5067
Johan Hedberga1443f52015-01-23 15:42:46 +02005068 hci_req_init(&req, hdev);
5069 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
5070 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005071 if (err < 0) {
5072 mgmt_pending_remove(cmd);
5073 goto failed;
5074 }
5075
5076failed:
5077 hci_dev_unlock(hdev);
5078 return err;
5079}
5080
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005081static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
5082 void *data, u16 len)
5083{
5084 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03005085 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005086 int err;
5087
5088 BT_DBG("request for %s", hdev->name);
5089
Johan Hedbergb97109792014-06-24 14:00:28 +03005090 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005091 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
5092 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005093
5094 hci_dev_lock(hdev);
5095
5096 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07005097 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005098 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005099 changed = hci_dev_test_and_clear_flag(hdev,
5100 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005101
Johan Hedbergb97109792014-06-24 14:00:28 +03005102 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07005103 use_changed = !hci_dev_test_and_set_flag(hdev,
5104 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005105 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005106 use_changed = hci_dev_test_and_clear_flag(hdev,
5107 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005108
5109 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005110 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03005111 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
5112 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
5113 sizeof(mode), &mode);
5114 }
5115
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005116 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
5117 if (err < 0)
5118 goto unlock;
5119
5120 if (changed)
5121 err = new_settings(hdev, sk);
5122
5123unlock:
5124 hci_dev_unlock(hdev);
5125 return err;
5126}
5127
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005128static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5129 u16 len)
5130{
5131 struct mgmt_cp_set_privacy *cp = cp_data;
5132 bool changed;
5133 int err;
5134
5135 BT_DBG("request for %s", hdev->name);
5136
5137 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005138 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5139 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005140
5141 if (cp->privacy != 0x00 && cp->privacy != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005142 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5143 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005144
5145 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005146 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5147 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005148
5149 hci_dev_lock(hdev);
5150
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005151 /* If user space supports this command it is also expected to
5152 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
5153 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005154 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005155
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005156 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005157 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005158 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005159 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005160 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005161 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005162 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005163 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005164 }
5165
5166 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
5167 if (err < 0)
5168 goto unlock;
5169
5170 if (changed)
5171 err = new_settings(hdev, sk);
5172
5173unlock:
5174 hci_dev_unlock(hdev);
5175 return err;
5176}
5177
Johan Hedberg41edf162014-02-18 10:19:35 +02005178static bool irk_is_valid(struct mgmt_irk_info *irk)
5179{
5180 switch (irk->addr.type) {
5181 case BDADDR_LE_PUBLIC:
5182 return true;
5183
5184 case BDADDR_LE_RANDOM:
5185 /* Two most significant bits shall be set */
5186 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5187 return false;
5188 return true;
5189 }
5190
5191 return false;
5192}
5193
5194static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5195 u16 len)
5196{
5197 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005198 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5199 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005200 u16 irk_count, expected_len;
5201 int i, err;
5202
5203 BT_DBG("request for %s", hdev->name);
5204
5205 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005206 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5207 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005208
5209 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005210 if (irk_count > max_irk_count) {
5211 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005212 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5213 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005214 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005215
5216 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
5217 if (expected_len != len) {
5218 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02005219 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005220 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5221 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005222 }
5223
5224 BT_DBG("%s irk_count %u", hdev->name, irk_count);
5225
5226 for (i = 0; i < irk_count; i++) {
5227 struct mgmt_irk_info *key = &cp->irks[i];
5228
5229 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005230 return mgmt_cmd_status(sk, hdev->id,
5231 MGMT_OP_LOAD_IRKS,
5232 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005233 }
5234
5235 hci_dev_lock(hdev);
5236
5237 hci_smp_irks_clear(hdev);
5238
5239 for (i = 0; i < irk_count; i++) {
5240 struct mgmt_irk_info *irk = &cp->irks[i];
5241 u8 addr_type;
5242
5243 if (irk->addr.type == BDADDR_LE_PUBLIC)
5244 addr_type = ADDR_LE_DEV_PUBLIC;
5245 else
5246 addr_type = ADDR_LE_DEV_RANDOM;
5247
5248 hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
5249 BDADDR_ANY);
5250 }
5251
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005252 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005253
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005254 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005255
5256 hci_dev_unlock(hdev);
5257
5258 return err;
5259}
5260
Johan Hedberg3f706b72013-01-20 14:27:16 +02005261static bool ltk_is_valid(struct mgmt_ltk_info *key)
5262{
5263 if (key->master != 0x00 && key->master != 0x01)
5264 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005265
5266 switch (key->addr.type) {
5267 case BDADDR_LE_PUBLIC:
5268 return true;
5269
5270 case BDADDR_LE_RANDOM:
5271 /* Two most significant bits shall be set */
5272 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5273 return false;
5274 return true;
5275 }
5276
5277 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005278}
5279
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005280static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005281 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005282{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005283 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005284 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5285 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005286 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005287 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005288
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005289 BT_DBG("request for %s", hdev->name);
5290
5291 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005292 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5293 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005294
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005295 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005296 if (key_count > max_key_count) {
5297 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005298 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5299 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005300 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005301
5302 expected_len = sizeof(*cp) + key_count *
5303 sizeof(struct mgmt_ltk_info);
5304 if (expected_len != len) {
5305 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02005306 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005307 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5308 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005309 }
5310
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005311 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005312
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005313 for (i = 0; i < key_count; i++) {
5314 struct mgmt_ltk_info *key = &cp->keys[i];
5315
Johan Hedberg3f706b72013-01-20 14:27:16 +02005316 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005317 return mgmt_cmd_status(sk, hdev->id,
5318 MGMT_OP_LOAD_LONG_TERM_KEYS,
5319 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005320 }
5321
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005322 hci_dev_lock(hdev);
5323
5324 hci_smp_ltks_clear(hdev);
5325
5326 for (i = 0; i < key_count; i++) {
5327 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedbergd7b25452014-05-23 13:19:53 +03005328 u8 type, addr_type, authenticated;
Marcel Holtmann79d95a12013-10-13 03:57:38 -07005329
5330 if (key->addr.type == BDADDR_LE_PUBLIC)
5331 addr_type = ADDR_LE_DEV_PUBLIC;
5332 else
5333 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005334
Johan Hedberg61b43352014-05-29 19:36:53 +03005335 switch (key->type) {
5336 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005337 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005338 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005339 break;
5340 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005341 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005342 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005343 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005344 case MGMT_LTK_P256_UNAUTH:
5345 authenticated = 0x00;
5346 type = SMP_LTK_P256;
5347 break;
5348 case MGMT_LTK_P256_AUTH:
5349 authenticated = 0x01;
5350 type = SMP_LTK_P256;
5351 break;
5352 case MGMT_LTK_P256_DEBUG:
5353 authenticated = 0x00;
5354 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03005355 default:
5356 continue;
5357 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005358
Johan Hedberg35d70272014-02-19 14:57:47 +02005359 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type,
Johan Hedbergd7b25452014-05-23 13:19:53 +03005360 authenticated, key->val, key->enc_size, key->ediv,
Johan Hedberg35d70272014-02-19 14:57:47 +02005361 key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005362 }
5363
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005364 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005365 NULL, 0);
5366
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005367 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005368
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005369 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005370}
5371
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005372static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005373{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005374 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005375 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005376 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005377
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005378 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005379
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005380 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005381 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005382 rp.tx_power = conn->tx_power;
5383 rp.max_tx_power = conn->max_tx_power;
5384 } else {
5385 rp.rssi = HCI_RSSI_INVALID;
5386 rp.tx_power = HCI_TX_POWER_INVALID;
5387 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005388 }
5389
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005390 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5391 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005392
5393 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005394 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005395
5396 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005397}
5398
Marcel Holtmann1904a852015-01-11 13:50:44 -08005399static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5400 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005401{
5402 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005403 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005404 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005405 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005406 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005407
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005408 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005409
5410 hci_dev_lock(hdev);
5411
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005412 /* Commands sent in request are either Read RSSI or Read Transmit Power
5413 * Level so we check which one was last sent to retrieve connection
5414 * handle. Both commands have handle as first parameter so it's safe to
5415 * cast data on the same command struct.
5416 *
5417 * First command sent is always Read RSSI and we fail only if it fails.
5418 * In other case we simply override error to indicate success as we
5419 * already remembered if TX power value is actually valid.
5420 */
5421 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5422 if (!cp) {
5423 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005424 status = MGMT_STATUS_SUCCESS;
5425 } else {
5426 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005427 }
5428
5429 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005430 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005431 goto unlock;
5432 }
5433
5434 handle = __le16_to_cpu(cp->handle);
5435 conn = hci_conn_hash_lookup_handle(hdev, handle);
5436 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005437 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005438 goto unlock;
5439 }
5440
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005441 cmd = mgmt_pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
5442 if (!cmd)
5443 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005444
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005445 cmd->cmd_complete(cmd, status);
5446 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005447
5448unlock:
5449 hci_dev_unlock(hdev);
5450}
5451
5452static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5453 u16 len)
5454{
5455 struct mgmt_cp_get_conn_info *cp = data;
5456 struct mgmt_rp_get_conn_info rp;
5457 struct hci_conn *conn;
5458 unsigned long conn_info_age;
5459 int err = 0;
5460
5461 BT_DBG("%s", hdev->name);
5462
5463 memset(&rp, 0, sizeof(rp));
5464 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5465 rp.addr.type = cp->addr.type;
5466
5467 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005468 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5469 MGMT_STATUS_INVALID_PARAMS,
5470 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005471
5472 hci_dev_lock(hdev);
5473
5474 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005475 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5476 MGMT_STATUS_NOT_POWERED, &rp,
5477 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005478 goto unlock;
5479 }
5480
5481 if (cp->addr.type == BDADDR_BREDR)
5482 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5483 &cp->addr.bdaddr);
5484 else
5485 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5486
5487 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005488 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5489 MGMT_STATUS_NOT_CONNECTED, &rp,
5490 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005491 goto unlock;
5492 }
5493
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005494 if (mgmt_pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005495 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5496 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005497 goto unlock;
5498 }
5499
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005500 /* To avoid client trying to guess when to poll again for information we
5501 * calculate conn info age as random value between min/max set in hdev.
5502 */
5503 conn_info_age = hdev->conn_info_min_age +
5504 prandom_u32_max(hdev->conn_info_max_age -
5505 hdev->conn_info_min_age);
5506
5507 /* Query controller to refresh cached values if they are too old or were
5508 * never read.
5509 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005510 if (time_after(jiffies, conn->conn_info_timestamp +
5511 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005512 !conn->conn_info_timestamp) {
5513 struct hci_request req;
5514 struct hci_cp_read_tx_power req_txp_cp;
5515 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005516 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005517
5518 hci_req_init(&req, hdev);
5519 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5520 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5521 &req_rssi_cp);
5522
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005523 /* For LE links TX power does not change thus we don't need to
5524 * query for it once value is known.
5525 */
5526 if (!bdaddr_type_is_le(cp->addr.type) ||
5527 conn->tx_power == HCI_TX_POWER_INVALID) {
5528 req_txp_cp.handle = cpu_to_le16(conn->handle);
5529 req_txp_cp.type = 0x00;
5530 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5531 sizeof(req_txp_cp), &req_txp_cp);
5532 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005533
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005534 /* Max TX power needs to be read only once per connection */
5535 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5536 req_txp_cp.handle = cpu_to_le16(conn->handle);
5537 req_txp_cp.type = 0x01;
5538 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5539 sizeof(req_txp_cp), &req_txp_cp);
5540 }
5541
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005542 err = hci_req_run(&req, conn_info_refresh_complete);
5543 if (err < 0)
5544 goto unlock;
5545
5546 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5547 data, len);
5548 if (!cmd) {
5549 err = -ENOMEM;
5550 goto unlock;
5551 }
5552
5553 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005554 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005555 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005556
5557 conn->conn_info_timestamp = jiffies;
5558 } else {
5559 /* Cache is valid, just reply with values cached in hci_conn */
5560 rp.rssi = conn->rssi;
5561 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005562 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005563
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005564 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5565 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005566 }
5567
5568unlock:
5569 hci_dev_unlock(hdev);
5570 return err;
5571}
5572
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005573static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005574{
5575 struct hci_conn *conn = cmd->user_data;
5576 struct mgmt_rp_get_clock_info rp;
5577 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005578 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005579
5580 memset(&rp, 0, sizeof(rp));
5581 memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
5582
5583 if (status)
5584 goto complete;
5585
5586 hdev = hci_dev_get(cmd->index);
5587 if (hdev) {
5588 rp.local_clock = cpu_to_le32(hdev->clock);
5589 hci_dev_put(hdev);
5590 }
5591
5592 if (conn) {
5593 rp.piconet_clock = cpu_to_le32(conn->clock);
5594 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5595 }
5596
5597complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005598 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5599 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005600
5601 if (conn) {
5602 hci_conn_drop(conn);
5603 hci_conn_put(conn);
5604 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005605
5606 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005607}
5608
Marcel Holtmann1904a852015-01-11 13:50:44 -08005609static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005610{
Johan Hedberg95868422014-06-28 17:54:07 +03005611 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005612 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005613 struct hci_conn *conn;
5614
5615 BT_DBG("%s status %u", hdev->name, status);
5616
5617 hci_dev_lock(hdev);
5618
5619 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5620 if (!hci_cp)
5621 goto unlock;
5622
5623 if (hci_cp->which) {
5624 u16 handle = __le16_to_cpu(hci_cp->handle);
5625 conn = hci_conn_hash_lookup_handle(hdev, handle);
5626 } else {
5627 conn = NULL;
5628 }
5629
5630 cmd = mgmt_pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
5631 if (!cmd)
5632 goto unlock;
5633
Johan Hedberg69487372014-12-05 13:36:07 +02005634 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005635 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005636
5637unlock:
5638 hci_dev_unlock(hdev);
5639}
5640
5641static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5642 u16 len)
5643{
5644 struct mgmt_cp_get_clock_info *cp = data;
5645 struct mgmt_rp_get_clock_info rp;
5646 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005647 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005648 struct hci_request req;
5649 struct hci_conn *conn;
5650 int err;
5651
5652 BT_DBG("%s", hdev->name);
5653
5654 memset(&rp, 0, sizeof(rp));
5655 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5656 rp.addr.type = cp->addr.type;
5657
5658 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005659 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5660 MGMT_STATUS_INVALID_PARAMS,
5661 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005662
5663 hci_dev_lock(hdev);
5664
5665 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005666 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5667 MGMT_STATUS_NOT_POWERED, &rp,
5668 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005669 goto unlock;
5670 }
5671
5672 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5673 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5674 &cp->addr.bdaddr);
5675 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005676 err = mgmt_cmd_complete(sk, hdev->id,
5677 MGMT_OP_GET_CLOCK_INFO,
5678 MGMT_STATUS_NOT_CONNECTED,
5679 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005680 goto unlock;
5681 }
5682 } else {
5683 conn = NULL;
5684 }
5685
5686 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5687 if (!cmd) {
5688 err = -ENOMEM;
5689 goto unlock;
5690 }
5691
Johan Hedberg69487372014-12-05 13:36:07 +02005692 cmd->cmd_complete = clock_info_cmd_complete;
5693
Johan Hedberg95868422014-06-28 17:54:07 +03005694 hci_req_init(&req, hdev);
5695
5696 memset(&hci_cp, 0, sizeof(hci_cp));
5697 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5698
5699 if (conn) {
5700 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005701 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005702
5703 hci_cp.handle = cpu_to_le16(conn->handle);
5704 hci_cp.which = 0x01; /* Piconet clock */
5705 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5706 }
5707
5708 err = hci_req_run(&req, get_clock_info_complete);
5709 if (err < 0)
5710 mgmt_pending_remove(cmd);
5711
5712unlock:
5713 hci_dev_unlock(hdev);
5714 return err;
5715}
5716
Johan Hedberg5a154e62014-12-19 22:26:02 +02005717static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5718{
5719 struct hci_conn *conn;
5720
5721 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5722 if (!conn)
5723 return false;
5724
5725 if (conn->dst_type != type)
5726 return false;
5727
5728 if (conn->state != BT_CONNECTED)
5729 return false;
5730
5731 return true;
5732}
5733
5734/* This function requires the caller holds hdev->lock */
5735static int hci_conn_params_set(struct hci_request *req, bdaddr_t *addr,
5736 u8 addr_type, u8 auto_connect)
5737{
5738 struct hci_dev *hdev = req->hdev;
5739 struct hci_conn_params *params;
5740
5741 params = hci_conn_params_add(hdev, addr, addr_type);
5742 if (!params)
5743 return -EIO;
5744
5745 if (params->auto_connect == auto_connect)
5746 return 0;
5747
5748 list_del_init(&params->action);
5749
5750 switch (auto_connect) {
5751 case HCI_AUTO_CONN_DISABLED:
5752 case HCI_AUTO_CONN_LINK_LOSS:
5753 __hci_update_background_scan(req);
5754 break;
5755 case HCI_AUTO_CONN_REPORT:
5756 list_add(&params->action, &hdev->pend_le_reports);
5757 __hci_update_background_scan(req);
5758 break;
5759 case HCI_AUTO_CONN_DIRECT:
5760 case HCI_AUTO_CONN_ALWAYS:
5761 if (!is_connected(hdev, addr, addr_type)) {
5762 list_add(&params->action, &hdev->pend_le_conns);
5763 __hci_update_background_scan(req);
5764 }
5765 break;
5766 }
5767
5768 params->auto_connect = auto_connect;
5769
5770 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5771 auto_connect);
5772
5773 return 0;
5774}
5775
Marcel Holtmann8afef092014-06-29 22:28:34 +02005776static void device_added(struct sock *sk, struct hci_dev *hdev,
5777 bdaddr_t *bdaddr, u8 type, u8 action)
5778{
5779 struct mgmt_ev_device_added ev;
5780
5781 bacpy(&ev.addr.bdaddr, bdaddr);
5782 ev.addr.type = type;
5783 ev.action = action;
5784
5785 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5786}
5787
Marcel Holtmann1904a852015-01-11 13:50:44 -08005788static void add_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg5a154e62014-12-19 22:26:02 +02005789{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005790 struct mgmt_pending_cmd *cmd;
Johan Hedberg5a154e62014-12-19 22:26:02 +02005791
5792 BT_DBG("status 0x%02x", status);
5793
5794 hci_dev_lock(hdev);
5795
5796 cmd = mgmt_pending_find(MGMT_OP_ADD_DEVICE, hdev);
5797 if (!cmd)
5798 goto unlock;
5799
5800 cmd->cmd_complete(cmd, mgmt_status(status));
5801 mgmt_pending_remove(cmd);
5802
5803unlock:
5804 hci_dev_unlock(hdev);
5805}
5806
Marcel Holtmann2faade52014-06-29 19:44:03 +02005807static int add_device(struct sock *sk, struct hci_dev *hdev,
5808 void *data, u16 len)
5809{
5810 struct mgmt_cp_add_device *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005811 struct mgmt_pending_cmd *cmd;
Johan Hedberg5a154e62014-12-19 22:26:02 +02005812 struct hci_request req;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005813 u8 auto_conn, addr_type;
5814 int err;
5815
5816 BT_DBG("%s", hdev->name);
5817
Johan Hedberg66593582014-07-09 12:59:14 +03005818 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005819 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005820 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5821 MGMT_STATUS_INVALID_PARAMS,
5822 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005823
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005824 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005825 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5826 MGMT_STATUS_INVALID_PARAMS,
5827 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005828
Johan Hedberg5a154e62014-12-19 22:26:02 +02005829 hci_req_init(&req, hdev);
5830
Marcel Holtmann2faade52014-06-29 19:44:03 +02005831 hci_dev_lock(hdev);
5832
Johan Hedberg5a154e62014-12-19 22:26:02 +02005833 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_DEVICE, hdev, data, len);
5834 if (!cmd) {
5835 err = -ENOMEM;
5836 goto unlock;
5837 }
5838
5839 cmd->cmd_complete = addr_cmd_complete;
5840
Johan Hedberg66593582014-07-09 12:59:14 +03005841 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005842 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005843 if (cp->action != 0x01) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005844 err = cmd->cmd_complete(cmd,
5845 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005846 mgmt_pending_remove(cmd);
Johan Hedberg66593582014-07-09 12:59:14 +03005847 goto unlock;
5848 }
5849
5850 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5851 cp->addr.type);
5852 if (err)
5853 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005854
Johan Hedberg5a154e62014-12-19 22:26:02 +02005855 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03005856
Johan Hedberg66593582014-07-09 12:59:14 +03005857 goto added;
5858 }
5859
Marcel Holtmann2faade52014-06-29 19:44:03 +02005860 if (cp->addr.type == BDADDR_LE_PUBLIC)
5861 addr_type = ADDR_LE_DEV_PUBLIC;
5862 else
5863 addr_type = ADDR_LE_DEV_RANDOM;
5864
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005865 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005866 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005867 else if (cp->action == 0x01)
5868 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005869 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005870 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005871
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005872 /* If the connection parameters don't exist for this device,
5873 * they will be created and configured with defaults.
5874 */
Johan Hedberg5a154e62014-12-19 22:26:02 +02005875 if (hci_conn_params_set(&req, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005876 auto_conn) < 0) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005877 err = cmd->cmd_complete(cmd, MGMT_STATUS_FAILED);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005878 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005879 goto unlock;
5880 }
5881
Johan Hedberg66593582014-07-09 12:59:14 +03005882added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005883 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5884
Johan Hedberg5a154e62014-12-19 22:26:02 +02005885 err = hci_req_run(&req, add_device_complete);
5886 if (err < 0) {
5887 /* ENODATA means no HCI commands were needed (e.g. if
5888 * the adapter is powered off).
5889 */
Johan Hedberg9df74652014-12-19 22:26:03 +02005890 if (err == -ENODATA)
5891 err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005892 mgmt_pending_remove(cmd);
5893 }
Marcel Holtmann2faade52014-06-29 19:44:03 +02005894
5895unlock:
5896 hci_dev_unlock(hdev);
5897 return err;
5898}
5899
Marcel Holtmann8afef092014-06-29 22:28:34 +02005900static void device_removed(struct sock *sk, struct hci_dev *hdev,
5901 bdaddr_t *bdaddr, u8 type)
5902{
5903 struct mgmt_ev_device_removed ev;
5904
5905 bacpy(&ev.addr.bdaddr, bdaddr);
5906 ev.addr.type = type;
5907
5908 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5909}
5910
Marcel Holtmann1904a852015-01-11 13:50:44 -08005911static void remove_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005912{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005913 struct mgmt_pending_cmd *cmd;
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005914
5915 BT_DBG("status 0x%02x", status);
5916
5917 hci_dev_lock(hdev);
5918
5919 cmd = mgmt_pending_find(MGMT_OP_REMOVE_DEVICE, hdev);
5920 if (!cmd)
5921 goto unlock;
5922
5923 cmd->cmd_complete(cmd, mgmt_status(status));
5924 mgmt_pending_remove(cmd);
5925
5926unlock:
5927 hci_dev_unlock(hdev);
5928}
5929
Marcel Holtmann2faade52014-06-29 19:44:03 +02005930static int remove_device(struct sock *sk, struct hci_dev *hdev,
5931 void *data, u16 len)
5932{
5933 struct mgmt_cp_remove_device *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005934 struct mgmt_pending_cmd *cmd;
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005935 struct hci_request req;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005936 int err;
5937
5938 BT_DBG("%s", hdev->name);
5939
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005940 hci_req_init(&req, hdev);
5941
Marcel Holtmann2faade52014-06-29 19:44:03 +02005942 hci_dev_lock(hdev);
5943
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005944 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_DEVICE, hdev, data, len);
5945 if (!cmd) {
5946 err = -ENOMEM;
5947 goto unlock;
5948 }
5949
5950 cmd->cmd_complete = addr_cmd_complete;
5951
Marcel Holtmann2faade52014-06-29 19:44:03 +02005952 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005953 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005954 u8 addr_type;
5955
Johan Hedberg66593582014-07-09 12:59:14 +03005956 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005957 err = cmd->cmd_complete(cmd,
5958 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005959 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005960 goto unlock;
5961 }
5962
Johan Hedberg66593582014-07-09 12:59:14 +03005963 if (cp->addr.type == BDADDR_BREDR) {
5964 err = hci_bdaddr_list_del(&hdev->whitelist,
5965 &cp->addr.bdaddr,
5966 cp->addr.type);
5967 if (err) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005968 err = cmd->cmd_complete(cmd,
5969 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005970 mgmt_pending_remove(cmd);
Johan Hedberg66593582014-07-09 12:59:14 +03005971 goto unlock;
5972 }
5973
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005974 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03005975
Johan Hedberg66593582014-07-09 12:59:14 +03005976 device_removed(sk, hdev, &cp->addr.bdaddr,
5977 cp->addr.type);
5978 goto complete;
5979 }
5980
Marcel Holtmann2faade52014-06-29 19:44:03 +02005981 if (cp->addr.type == BDADDR_LE_PUBLIC)
5982 addr_type = ADDR_LE_DEV_PUBLIC;
5983 else
5984 addr_type = ADDR_LE_DEV_RANDOM;
5985
Johan Hedbergc71593d2014-07-02 17:37:28 +03005986 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
5987 addr_type);
5988 if (!params) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005989 err = cmd->cmd_complete(cmd,
5990 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005991 mgmt_pending_remove(cmd);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005992 goto unlock;
5993 }
5994
5995 if (params->auto_connect == HCI_AUTO_CONN_DISABLED) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005996 err = cmd->cmd_complete(cmd,
5997 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005998 mgmt_pending_remove(cmd);
Johan Hedbergc71593d2014-07-02 17:37:28 +03005999 goto unlock;
6000 }
6001
Johan Hedbergd1dbf122014-07-04 16:17:23 +03006002 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006003 list_del(&params->list);
6004 kfree(params);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006005 __hci_update_background_scan(&req);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006006
6007 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006008 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03006009 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03006010 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03006011
Marcel Holtmann2faade52014-06-29 19:44:03 +02006012 if (cp->addr.type) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006013 err = cmd->cmd_complete(cmd,
6014 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006015 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006016 goto unlock;
6017 }
6018
Johan Hedberg66593582014-07-09 12:59:14 +03006019 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
6020 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
6021 list_del(&b->list);
6022 kfree(b);
6023 }
6024
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006025 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03006026
Johan Hedberg19de0822014-07-06 13:06:51 +03006027 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
6028 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
6029 continue;
6030 device_removed(sk, hdev, &p->addr, p->addr_type);
6031 list_del(&p->action);
6032 list_del(&p->list);
6033 kfree(p);
6034 }
6035
6036 BT_DBG("All LE connection parameters were removed");
6037
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006038 __hci_update_background_scan(&req);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006039 }
6040
Johan Hedberg66593582014-07-09 12:59:14 +03006041complete:
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006042 err = hci_req_run(&req, remove_device_complete);
6043 if (err < 0) {
6044 /* ENODATA means no HCI commands were needed (e.g. if
6045 * the adapter is powered off).
6046 */
Johan Hedberg9df74652014-12-19 22:26:03 +02006047 if (err == -ENODATA)
6048 err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006049 mgmt_pending_remove(cmd);
6050 }
Marcel Holtmann2faade52014-06-29 19:44:03 +02006051
6052unlock:
6053 hci_dev_unlock(hdev);
6054 return err;
6055}
6056
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006057static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
6058 u16 len)
6059{
6060 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006061 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
6062 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006063 u16 param_count, expected_len;
6064 int i;
6065
6066 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006067 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6068 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006069
6070 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006071 if (param_count > max_param_count) {
6072 BT_ERR("load_conn_param: too big param_count value %u",
6073 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006074 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6075 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006076 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006077
6078 expected_len = sizeof(*cp) + param_count *
6079 sizeof(struct mgmt_conn_param);
6080 if (expected_len != len) {
6081 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
6082 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006083 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6084 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006085 }
6086
6087 BT_DBG("%s param_count %u", hdev->name, param_count);
6088
6089 hci_dev_lock(hdev);
6090
6091 hci_conn_params_clear_disabled(hdev);
6092
6093 for (i = 0; i < param_count; i++) {
6094 struct mgmt_conn_param *param = &cp->params[i];
6095 struct hci_conn_params *hci_param;
6096 u16 min, max, latency, timeout;
6097 u8 addr_type;
6098
6099 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
6100 param->addr.type);
6101
6102 if (param->addr.type == BDADDR_LE_PUBLIC) {
6103 addr_type = ADDR_LE_DEV_PUBLIC;
6104 } else if (param->addr.type == BDADDR_LE_RANDOM) {
6105 addr_type = ADDR_LE_DEV_RANDOM;
6106 } else {
6107 BT_ERR("Ignoring invalid connection parameters");
6108 continue;
6109 }
6110
6111 min = le16_to_cpu(param->min_interval);
6112 max = le16_to_cpu(param->max_interval);
6113 latency = le16_to_cpu(param->latency);
6114 timeout = le16_to_cpu(param->timeout);
6115
6116 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6117 min, max, latency, timeout);
6118
6119 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
6120 BT_ERR("Ignoring invalid connection parameters");
6121 continue;
6122 }
6123
6124 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
6125 addr_type);
6126 if (!hci_param) {
6127 BT_ERR("Failed to add connection parameters");
6128 continue;
6129 }
6130
6131 hci_param->conn_min_interval = min;
6132 hci_param->conn_max_interval = max;
6133 hci_param->conn_latency = latency;
6134 hci_param->supervision_timeout = timeout;
6135 }
6136
6137 hci_dev_unlock(hdev);
6138
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006139 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
6140 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006141}
6142
Marcel Holtmanndbece372014-07-04 18:11:55 +02006143static int set_external_config(struct sock *sk, struct hci_dev *hdev,
6144 void *data, u16 len)
6145{
6146 struct mgmt_cp_set_external_config *cp = data;
6147 bool changed;
6148 int err;
6149
6150 BT_DBG("%s", hdev->name);
6151
6152 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006153 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6154 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006155
6156 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006157 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6158 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006159
6160 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02006161 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6162 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006163
6164 hci_dev_lock(hdev);
6165
6166 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07006167 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006168 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006169 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006170
6171 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
6172 if (err < 0)
6173 goto unlock;
6174
6175 if (!changed)
6176 goto unlock;
6177
Marcel Holtmannf4537c02014-07-04 19:06:23 +02006178 err = new_options(hdev, sk);
6179
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006180 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02006181 mgmt_index_removed(hdev);
Marcel Holtmannd603b762014-07-06 12:11:14 +02006182
Marcel Holtmann516018a2015-03-13 02:11:04 -07006183 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006184 hci_dev_set_flag(hdev, HCI_CONFIG);
6185 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b762014-07-06 12:11:14 +02006186
6187 queue_work(hdev->req_workqueue, &hdev->power_on);
6188 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02006189 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b762014-07-06 12:11:14 +02006190 mgmt_index_added(hdev);
6191 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02006192 }
6193
6194unlock:
6195 hci_dev_unlock(hdev);
6196 return err;
6197}
6198
Marcel Holtmann9713c172014-07-06 12:11:15 +02006199static int set_public_address(struct sock *sk, struct hci_dev *hdev,
6200 void *data, u16 len)
6201{
6202 struct mgmt_cp_set_public_address *cp = data;
6203 bool changed;
6204 int err;
6205
6206 BT_DBG("%s", hdev->name);
6207
6208 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006209 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6210 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006211
6212 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02006213 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6214 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006215
6216 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02006217 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6218 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006219
6220 hci_dev_lock(hdev);
6221
6222 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
6223 bacpy(&hdev->public_addr, &cp->bdaddr);
6224
6225 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
6226 if (err < 0)
6227 goto unlock;
6228
6229 if (!changed)
6230 goto unlock;
6231
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006232 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006233 err = new_options(hdev, sk);
6234
6235 if (is_configured(hdev)) {
6236 mgmt_index_removed(hdev);
6237
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006238 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006239
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006240 hci_dev_set_flag(hdev, HCI_CONFIG);
6241 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006242
6243 queue_work(hdev->req_workqueue, &hdev->power_on);
6244 }
6245
6246unlock:
6247 hci_dev_unlock(hdev);
6248 return err;
6249}
6250
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006251static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006252 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006253 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006254 HCI_MGMT_NO_HDEV |
6255 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006256 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006257 HCI_MGMT_NO_HDEV |
6258 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006259 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006260 HCI_MGMT_NO_HDEV |
6261 HCI_MGMT_UNTRUSTED },
6262 { read_controller_info, MGMT_READ_INFO_SIZE,
6263 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006264 { set_powered, MGMT_SETTING_SIZE },
6265 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6266 { set_connectable, MGMT_SETTING_SIZE },
6267 { set_fast_connectable, MGMT_SETTING_SIZE },
6268 { set_bondable, MGMT_SETTING_SIZE },
6269 { set_link_security, MGMT_SETTING_SIZE },
6270 { set_ssp, MGMT_SETTING_SIZE },
6271 { set_hs, MGMT_SETTING_SIZE },
6272 { set_le, MGMT_SETTING_SIZE },
6273 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6274 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6275 { add_uuid, MGMT_ADD_UUID_SIZE },
6276 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006277 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6278 HCI_MGMT_VAR_LEN },
6279 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6280 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006281 { disconnect, MGMT_DISCONNECT_SIZE },
6282 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6283 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6284 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6285 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6286 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6287 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6288 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6289 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6290 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6291 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6292 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006293 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6294 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6295 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006296 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6297 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6298 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6299 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6300 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6301 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6302 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6303 { set_advertising, MGMT_SETTING_SIZE },
6304 { set_bredr, MGMT_SETTING_SIZE },
6305 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6306 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6307 { set_secure_conn, MGMT_SETTING_SIZE },
6308 { set_debug_keys, MGMT_SETTING_SIZE },
6309 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006310 { load_irks, MGMT_LOAD_IRKS_SIZE,
6311 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006312 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6313 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6314 { add_device, MGMT_ADD_DEVICE_SIZE },
6315 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006316 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6317 HCI_MGMT_VAR_LEN },
6318 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006319 HCI_MGMT_NO_HDEV |
6320 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006321 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006322 HCI_MGMT_UNCONFIGURED |
6323 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006324 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6325 HCI_MGMT_UNCONFIGURED },
6326 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6327 HCI_MGMT_UNCONFIGURED },
6328 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6329 HCI_MGMT_VAR_LEN },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006330 { NULL },
6331 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006332 HCI_MGMT_NO_HDEV |
6333 HCI_MGMT_UNTRUSTED },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006334};
6335
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006336int mgmt_control(struct hci_mgmt_chan *chan, struct sock *sk,
6337 struct msghdr *msg, size_t msglen)
Johan Hedberg03811012010-12-08 00:21:06 +02006338{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03006339 void *buf;
6340 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02006341 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01006342 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006343 struct hci_dev *hdev = NULL;
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006344 const struct hci_mgmt_handler *handler;
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006345 bool var_len, no_hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02006346 int err;
6347
6348 BT_DBG("got %zu bytes", msglen);
6349
6350 if (msglen < sizeof(*hdr))
6351 return -EINVAL;
6352
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03006353 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02006354 if (!buf)
6355 return -ENOMEM;
6356
Al Viro6ce8e9c2014-04-06 21:25:44 -04006357 if (memcpy_from_msg(buf, msg, msglen)) {
Johan Hedberg03811012010-12-08 00:21:06 +02006358 err = -EFAULT;
6359 goto done;
6360 }
6361
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03006362 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07006363 opcode = __le16_to_cpu(hdr->opcode);
6364 index = __le16_to_cpu(hdr->index);
6365 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02006366
6367 if (len != msglen - sizeof(*hdr)) {
6368 err = -EINVAL;
6369 goto done;
6370 }
6371
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006372 if (opcode >= chan->handler_count ||
6373 chan->handlers[opcode].func == NULL) {
6374 BT_DBG("Unknown op %u", opcode);
Johan Hedberga69e8372015-03-06 21:08:53 +02006375 err = mgmt_cmd_status(sk, index, opcode,
6376 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006377 goto done;
6378 }
6379
6380 handler = &chan->handlers[opcode];
6381
Marcel Holtmannc927a102015-03-14 19:28:03 -07006382 if (!hci_sock_test_flag(sk, HCI_SOCK_TRUSTED) &&
6383 !(handler->flags & HCI_MGMT_UNTRUSTED)) {
6384 err = mgmt_cmd_status(sk, index, opcode,
6385 MGMT_STATUS_PERMISSION_DENIED);
6386 goto done;
6387 }
6388
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006389 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006390 hdev = hci_dev_get(index);
6391 if (!hdev) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006392 err = mgmt_cmd_status(sk, index, opcode,
6393 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006394 goto done;
6395 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07006396
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006397 if (hci_dev_test_flag(hdev, HCI_SETUP) ||
6398 hci_dev_test_flag(hdev, HCI_CONFIG) ||
6399 hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006400 err = mgmt_cmd_status(sk, index, opcode,
6401 MGMT_STATUS_INVALID_INDEX);
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07006402 goto done;
6403 }
Marcel Holtmann42a9bc142014-07-04 16:54:40 +02006404
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006405 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006406 !(handler->flags & HCI_MGMT_UNCONFIGURED)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006407 err = mgmt_cmd_status(sk, index, opcode,
6408 MGMT_STATUS_INVALID_INDEX);
Marcel Holtmann42a9bc142014-07-04 16:54:40 +02006409 goto done;
6410 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006411 }
6412
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006413 no_hdev = (handler->flags & HCI_MGMT_NO_HDEV);
6414 if (no_hdev != !hdev) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006415 err = mgmt_cmd_status(sk, index, opcode,
6416 MGMT_STATUS_INVALID_INDEX);
Marcel Holtmann73d1df22014-07-02 22:10:52 +02006417 goto done;
6418 }
6419
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006420 var_len = (handler->flags & HCI_MGMT_VAR_LEN);
6421 if ((var_len && len < handler->data_len) ||
6422 (!var_len && len != handler->data_len)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006423 err = mgmt_cmd_status(sk, index, opcode,
6424 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02006425 goto done;
6426 }
6427
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006428 if (hdev)
6429 mgmt_init_hdev(sk, hdev);
6430
6431 cp = buf + sizeof(*hdr);
6432
Johan Hedbergbe22b542012-03-01 22:24:41 +02006433 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02006434 if (err < 0)
6435 goto done;
6436
Johan Hedberg03811012010-12-08 00:21:06 +02006437 err = msglen;
6438
6439done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006440 if (hdev)
6441 hci_dev_put(hdev);
6442
Johan Hedberg03811012010-12-08 00:21:06 +02006443 kfree(buf);
6444 return err;
6445}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006446
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006447void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006448{
Marcel Holtmannced85542015-03-14 19:27:56 -07006449 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006450
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006451 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6452 return;
6453
Marcel Holtmannf9207332015-03-14 19:27:55 -07006454 switch (hdev->dev_type) {
6455 case HCI_BREDR:
6456 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6457 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6458 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006459 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006460 } else {
6461 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6462 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006463 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006464 }
6465 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006466 case HCI_AMP:
6467 ev.type = 0x02;
6468 break;
6469 default:
6470 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006471 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006472
6473 ev.bus = hdev->bus;
6474
6475 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6476 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006477}
6478
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006479void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006480{
Marcel Holtmannced85542015-03-14 19:27:56 -07006481 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006482 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006483
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006484 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6485 return;
6486
Marcel Holtmannf9207332015-03-14 19:27:55 -07006487 switch (hdev->dev_type) {
6488 case HCI_BREDR:
6489 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006490
Marcel Holtmannf9207332015-03-14 19:27:55 -07006491 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6492 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6493 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006494 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006495 } else {
6496 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6497 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006498 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006499 }
6500 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006501 case HCI_AMP:
6502 ev.type = 0x02;
6503 break;
6504 default:
6505 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006506 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006507
6508 ev.bus = hdev->bus;
6509
6510 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6511 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006512}
6513
Andre Guedes6046dc32014-02-26 20:21:51 -03006514/* This function requires the caller holds hdev->lock */
Johan Hedberg2cf22212014-12-19 22:26:00 +02006515static void restart_le_actions(struct hci_request *req)
Andre Guedes6046dc32014-02-26 20:21:51 -03006516{
Johan Hedberg2cf22212014-12-19 22:26:00 +02006517 struct hci_dev *hdev = req->hdev;
Andre Guedes6046dc32014-02-26 20:21:51 -03006518 struct hci_conn_params *p;
6519
6520 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006521 /* Needed for AUTO_OFF case where might not "really"
6522 * have been powered off.
6523 */
6524 list_del_init(&p->action);
6525
6526 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006527 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006528 case HCI_AUTO_CONN_ALWAYS:
6529 list_add(&p->action, &hdev->pend_le_conns);
6530 break;
6531 case HCI_AUTO_CONN_REPORT:
6532 list_add(&p->action, &hdev->pend_le_reports);
6533 break;
6534 default:
6535 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006536 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006537 }
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006538
Johan Hedberg2cf22212014-12-19 22:26:00 +02006539 __hci_update_background_scan(req);
Andre Guedes6046dc32014-02-26 20:21:51 -03006540}
6541
Marcel Holtmann1904a852015-01-11 13:50:44 -08006542static void powered_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg229ab392013-03-15 17:06:53 -05006543{
6544 struct cmd_lookup match = { NULL, hdev };
6545
6546 BT_DBG("status 0x%02x", status);
6547
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006548 if (!status) {
6549 /* Register the available SMP channels (BR/EDR and LE) only
6550 * when successfully powering on the controller. This late
6551 * registration is required so that LE SMP can clearly
6552 * decide if the public address or static address is used.
6553 */
6554 smp_register(hdev);
6555 }
6556
Johan Hedberg229ab392013-03-15 17:06:53 -05006557 hci_dev_lock(hdev);
6558
6559 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6560
6561 new_settings(hdev, match.sk);
6562
6563 hci_dev_unlock(hdev);
6564
6565 if (match.sk)
6566 sock_put(match.sk);
6567}
6568
Johan Hedberg70da6242013-03-15 17:06:51 -05006569static int powered_update_hci(struct hci_dev *hdev)
6570{
Johan Hedberg890ea892013-03-15 17:06:52 -05006571 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05006572 u8 link_sec;
6573
Johan Hedberg890ea892013-03-15 17:06:52 -05006574 hci_req_init(&req, hdev);
6575
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006576 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED) &&
Johan Hedberg70da6242013-03-15 17:06:51 -05006577 !lmp_host_ssp_capable(hdev)) {
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006578 u8 mode = 0x01;
Johan Hedberg70da6242013-03-15 17:06:51 -05006579
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006580 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
Johan Hedberg70da6242013-03-15 17:06:51 -05006581
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006582 if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) {
6583 u8 support = 0x01;
6584
6585 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT,
6586 sizeof(support), &support);
6587 }
Johan Hedbergec6f99b2014-12-12 13:30:11 +02006588 }
6589
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006590 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
Johan Hedbergc73eee92013-04-19 18:35:21 +03006591 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05006592 struct hci_cp_write_le_host_supported cp;
6593
Marcel Holtmann32226e42014-07-24 20:04:16 +02006594 cp.le = 0x01;
6595 cp.simul = 0x00;
Johan Hedberg70da6242013-03-15 17:06:51 -05006596
6597 /* Check first if we already have the right
6598 * host state (host features set)
6599 */
6600 if (cp.le != lmp_host_le_capable(hdev) ||
6601 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05006602 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
6603 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05006604 }
6605
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07006606 if (lmp_le_capable(hdev)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006607 /* Make sure the controller has a good default for
6608 * advertising data. This also applies to the case
6609 * where BR/EDR was toggled during the AUTO_OFF phase.
6610 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006611 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07006612 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07006613 update_scan_rsp_data(&req);
6614 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006615
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006616 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07006617 enable_advertising(&req);
Johan Hedberg2cf22212014-12-19 22:26:00 +02006618
6619 restart_le_actions(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03006620 }
6621
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006622 link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg70da6242013-03-15 17:06:51 -05006623 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05006624 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
6625 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05006626
6627 if (lmp_bredr_capable(hdev)) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006628 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg406ef2a2015-03-10 20:14:27 +02006629 write_fast_connectable(&req, true);
6630 else
6631 write_fast_connectable(&req, false);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02006632 __hci_update_page_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006633 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05006634 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006635 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05006636 }
6637
Johan Hedberg229ab392013-03-15 17:06:53 -05006638 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05006639}
6640
Johan Hedberg744cf192011-11-08 20:40:14 +02006641int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006642{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006643 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006644 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006645 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006646
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006647 if (!hci_dev_test_flag(hdev, HCI_MGMT))
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006648 return 0;
6649
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006650 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05006651 if (powered_update_hci(hdev) == 0)
6652 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02006653
Johan Hedberg229ab392013-03-15 17:06:53 -05006654 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
6655 &match);
6656 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006657 }
6658
Johan Hedberg229ab392013-03-15 17:06:53 -05006659 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006660
6661 /* If the power off is because of hdev unregistration let
6662 * use the appropriate INVALID_INDEX status. Otherwise use
6663 * NOT_POWERED. We cover both scenarios here since later in
6664 * mgmt_index_removed() any hci_conn callbacks will have already
6665 * been triggered, potentially causing misleading DISCONNECTED
6666 * status responses.
6667 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006668 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006669 status = MGMT_STATUS_INVALID_INDEX;
6670 else
6671 status = MGMT_STATUS_NOT_POWERED;
6672
6673 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006674
6675 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
6676 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6677 zero_cod, sizeof(zero_cod), NULL);
6678
6679new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02006680 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006681
6682 if (match.sk)
6683 sock_put(match.sk);
6684
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006685 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006686}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006687
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006688void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006689{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006690 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006691 u8 status;
6692
6693 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
6694 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006695 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006696
6697 if (err == -ERFKILL)
6698 status = MGMT_STATUS_RFKILLED;
6699 else
6700 status = MGMT_STATUS_FAILED;
6701
Johan Hedberga69e8372015-03-06 21:08:53 +02006702 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006703
6704 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006705}
6706
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006707void mgmt_discoverable_timeout(struct hci_dev *hdev)
6708{
6709 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006710
6711 hci_dev_lock(hdev);
6712
6713 /* When discoverable timeout triggers, then just make sure
6714 * the limited discoverable flag is cleared. Even in the case
6715 * of a timeout triggered from general discoverable, it is
6716 * safe to unconditionally clear the flag.
6717 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006718 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
6719 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006720
6721 hci_req_init(&req, hdev);
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006722 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg4b580612013-10-19 23:38:21 +03006723 u8 scan = SCAN_PAGE;
6724 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
6725 sizeof(scan), &scan);
6726 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006727 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03006728 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006729 hci_req_run(&req, NULL);
6730
6731 hdev->discov_timeout = 0;
6732
Johan Hedberg9a43e252013-10-20 19:00:07 +03006733 new_settings(hdev, NULL);
6734
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006735 hci_dev_unlock(hdev);
6736}
6737
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006738void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
6739 bool persistent)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02006740{
Johan Hedberg86742e12011-11-07 23:13:38 +02006741 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02006742
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006743 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02006744
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006745 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02006746 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006747 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006748 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03006749 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006750 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02006751
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006752 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02006753}
Johan Hedbergf7520542011-01-20 12:34:39 +02006754
Johan Hedbergd7b25452014-05-23 13:19:53 +03006755static u8 mgmt_ltk_type(struct smp_ltk *ltk)
6756{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006757 switch (ltk->type) {
6758 case SMP_LTK:
6759 case SMP_LTK_SLAVE:
6760 if (ltk->authenticated)
6761 return MGMT_LTK_AUTHENTICATED;
6762 return MGMT_LTK_UNAUTHENTICATED;
6763 case SMP_LTK_P256:
6764 if (ltk->authenticated)
6765 return MGMT_LTK_P256_AUTH;
6766 return MGMT_LTK_P256_UNAUTH;
6767 case SMP_LTK_P256_DEBUG:
6768 return MGMT_LTK_P256_DEBUG;
6769 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006770
6771 return MGMT_LTK_UNAUTHENTICATED;
6772}
6773
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006774void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006775{
6776 struct mgmt_ev_new_long_term_key ev;
6777
6778 memset(&ev, 0, sizeof(ev));
6779
Marcel Holtmann5192d302014-02-19 17:11:58 -08006780 /* Devices using resolvable or non-resolvable random addresses
6781 * without providing an indentity resolving key don't require
6782 * to store long term keys. Their addresses will change the
6783 * next time around.
6784 *
6785 * Only when a remote device provides an identity address
6786 * make sure the long term key is stored. If the remote
6787 * identity is known, the long term keys are internally
6788 * mapped to the identity address. So allow static random
6789 * and public addresses here.
6790 */
Johan Hedbergba74b662014-02-19 14:57:45 +02006791 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6792 (key->bdaddr.b[5] & 0xc0) != 0xc0)
6793 ev.store_hint = 0x00;
6794 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006795 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02006796
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006797 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006798 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03006799 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006800 ev.key.enc_size = key->enc_size;
6801 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08006802 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006803
Johan Hedberg2ceba532014-06-16 19:25:16 +03006804 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006805 ev.key.master = 1;
6806
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006807 memcpy(ev.key.val, key->val, sizeof(key->val));
6808
Marcel Holtmann083368f2013-10-15 14:26:29 -07006809 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006810}
6811
Johan Hedberg95fbac82014-02-19 15:18:31 +02006812void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk)
6813{
6814 struct mgmt_ev_new_irk ev;
6815
6816 memset(&ev, 0, sizeof(ev));
6817
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08006818 /* For identity resolving keys from devices that are already
6819 * using a public address or static random address, do not
6820 * ask for storing this key. The identity resolving key really
6821 * is only mandatory for devices using resovlable random
6822 * addresses.
6823 *
6824 * Storing all identity resolving keys has the downside that
6825 * they will be also loaded on next boot of they system. More
6826 * identity resolving keys, means more time during scanning is
6827 * needed to actually resolve these addresses.
6828 */
6829 if (bacmp(&irk->rpa, BDADDR_ANY))
6830 ev.store_hint = 0x01;
6831 else
6832 ev.store_hint = 0x00;
6833
Johan Hedberg95fbac82014-02-19 15:18:31 +02006834 bacpy(&ev.rpa, &irk->rpa);
6835 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
6836 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
6837 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
6838
6839 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
6840}
6841
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006842void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
6843 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006844{
6845 struct mgmt_ev_new_csrk ev;
6846
6847 memset(&ev, 0, sizeof(ev));
6848
6849 /* Devices using resolvable or non-resolvable random addresses
6850 * without providing an indentity resolving key don't require
6851 * to store signature resolving keys. Their addresses will change
6852 * the next time around.
6853 *
6854 * Only when a remote device provides an identity address
6855 * make sure the signature resolving key is stored. So allow
6856 * static random and public addresses here.
6857 */
6858 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6859 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
6860 ev.store_hint = 0x00;
6861 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006862 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006863
6864 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
6865 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02006866 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07006867 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
6868
6869 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
6870}
6871
Andre Guedesffb5a8272014-07-01 18:10:11 -03006872void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03006873 u8 bdaddr_type, u8 store_hint, u16 min_interval,
6874 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03006875{
6876 struct mgmt_ev_new_conn_param ev;
6877
Johan Hedbergc103aea2014-07-02 17:37:34 +03006878 if (!hci_is_identity_address(bdaddr, bdaddr_type))
6879 return;
6880
Andre Guedesffb5a8272014-07-01 18:10:11 -03006881 memset(&ev, 0, sizeof(ev));
6882 bacpy(&ev.addr.bdaddr, bdaddr);
6883 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03006884 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03006885 ev.min_interval = cpu_to_le16(min_interval);
6886 ev.max_interval = cpu_to_le16(max_interval);
6887 ev.latency = cpu_to_le16(latency);
6888 ev.timeout = cpu_to_le16(timeout);
6889
6890 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
6891}
6892
Marcel Holtmann94933992013-10-15 10:26:39 -07006893static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
6894 u8 data_len)
6895{
6896 eir[eir_len++] = sizeof(type) + data_len;
6897 eir[eir_len++] = type;
6898 memcpy(&eir[eir_len], data, data_len);
6899 eir_len += data_len;
6900
6901 return eir_len;
6902}
6903
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006904void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
6905 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02006906{
Johan Hedbergb644ba32012-01-17 21:48:47 +02006907 char buf[512];
6908 struct mgmt_ev_device_connected *ev = (void *) buf;
6909 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02006910
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00006911 bacpy(&ev->addr.bdaddr, &conn->dst);
6912 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02006913
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02006914 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02006915
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006916 /* We must ensure that the EIR Data fields are ordered and
6917 * unique. Keep it simple for now and avoid the problem by not
6918 * adding any BR/EDR data to the LE adv.
6919 */
6920 if (conn->le_adv_data_len > 0) {
6921 memcpy(&ev->eir[eir_len],
6922 conn->le_adv_data, conn->le_adv_data_len);
6923 eir_len = conn->le_adv_data_len;
6924 } else {
6925 if (name_len > 0)
6926 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
6927 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006928
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00006929 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00006930 eir_len = eir_append_data(ev->eir, eir_len,
6931 EIR_CLASS_OF_DEV,
6932 conn->dev_class, 3);
6933 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02006934
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02006935 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02006936
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07006937 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
6938 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02006939}
6940
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006941static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02006942{
Johan Hedberg8962ee72011-01-20 12:40:27 +02006943 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006944
Johan Hedbergf5818c22014-12-05 13:36:02 +02006945 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006946
6947 *sk = cmd->sk;
6948 sock_hold(*sk);
6949
Johan Hedberga664b5b2011-02-19 12:06:02 -03006950 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02006951}
6952
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006953static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02006954{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006955 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02006956 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02006957
Johan Hedbergb1078ad2012-02-09 17:21:16 +02006958 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
6959
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02006960 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02006961 mgmt_pending_remove(cmd);
6962}
6963
Johan Hedberg84c61d92014-08-01 11:13:30 +03006964bool mgmt_powering_down(struct hci_dev *hdev)
6965{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006966 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03006967 struct mgmt_mode *cp;
6968
6969 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
6970 if (!cmd)
6971 return false;
6972
6973 cp = cmd->param;
6974 if (!cp->val)
6975 return true;
6976
6977 return false;
6978}
6979
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07006980void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006981 u8 link_type, u8 addr_type, u8 reason,
6982 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02006983{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02006984 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006985 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02006986
Johan Hedberg84c61d92014-08-01 11:13:30 +03006987 /* The connection is still in hci_conn_hash so test for 1
6988 * instead of 0 to know if this is the last one.
6989 */
6990 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
6991 cancel_delayed_work(&hdev->power_off);
6992 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02006993 }
6994
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02006995 if (!mgmt_connected)
6996 return;
6997
Andre Guedes57eb7762013-10-30 19:01:41 -03006998 if (link_type != ACL_LINK && link_type != LE_LINK)
6999 return;
7000
Johan Hedberg744cf192011-11-08 20:40:14 +02007001 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007002
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007003 bacpy(&ev.addr.bdaddr, bdaddr);
7004 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7005 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007006
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007007 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007008
7009 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007010 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007011
Johan Hedberg124f6e32012-02-09 13:50:12 +02007012 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007013 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007014}
7015
Marcel Holtmann78929242013-10-06 23:55:47 -07007016void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7017 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007018{
Andre Guedes3655bba2013-10-30 19:01:40 -03007019 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7020 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007021 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007022
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007023 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7024 hdev);
7025
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007026 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007027 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007028 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007029
Andre Guedes3655bba2013-10-30 19:01:40 -03007030 cp = cmd->param;
7031
7032 if (bacmp(bdaddr, &cp->addr.bdaddr))
7033 return;
7034
7035 if (cp->addr.type != bdaddr_type)
7036 return;
7037
Johan Hedbergf5818c22014-12-05 13:36:02 +02007038 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007039 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007040}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007041
Marcel Holtmann445608d2013-10-06 23:55:48 -07007042void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7043 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007044{
7045 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007046
Johan Hedberg84c61d92014-08-01 11:13:30 +03007047 /* The connection is still in hci_conn_hash so test for 1
7048 * instead of 0 to know if this is the last one.
7049 */
7050 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7051 cancel_delayed_work(&hdev->power_off);
7052 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007053 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007054
Johan Hedberg4c659c32011-11-07 23:13:39 +02007055 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007056 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007057 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007058
Marcel Holtmann445608d2013-10-06 23:55:48 -07007059 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007060}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007061
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007062void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007063{
7064 struct mgmt_ev_pin_code_request ev;
7065
Johan Hedbergd8457692012-02-17 14:24:57 +02007066 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007067 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007068 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007069
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007070 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007071}
7072
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007073void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7074 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007075{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007076 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007077
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007078 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007079 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007080 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007081
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007082 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007083 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007084}
7085
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007086void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7087 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007088{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007089 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007090
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007091 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007092 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007093 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007094
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007095 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007096 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007097}
Johan Hedberga5c29682011-02-19 12:05:57 -03007098
Johan Hedberg744cf192011-11-08 20:40:14 +02007099int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007100 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007101 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007102{
7103 struct mgmt_ev_user_confirm_request ev;
7104
Johan Hedberg744cf192011-11-08 20:40:14 +02007105 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007106
Johan Hedberg272d90d2012-02-09 15:26:12 +02007107 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007108 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007109 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007110 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007111
Johan Hedberg744cf192011-11-08 20:40:14 +02007112 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007113 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007114}
7115
Johan Hedberg272d90d2012-02-09 15:26:12 +02007116int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007117 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007118{
7119 struct mgmt_ev_user_passkey_request ev;
7120
7121 BT_DBG("%s", hdev->name);
7122
Johan Hedberg272d90d2012-02-09 15:26:12 +02007123 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007124 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007125
7126 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007127 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007128}
7129
Brian Gix0df4c182011-11-16 13:53:13 -08007130static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007131 u8 link_type, u8 addr_type, u8 status,
7132 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007133{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007134 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007135
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007136 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007137 if (!cmd)
7138 return -ENOENT;
7139
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007140 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007141 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007142
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007143 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007144}
7145
Johan Hedberg744cf192011-11-08 20:40:14 +02007146int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007147 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007148{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007149 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007150 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007151}
7152
Johan Hedberg272d90d2012-02-09 15:26:12 +02007153int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007154 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007155{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007156 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007157 status,
7158 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007159}
Johan Hedberg2a611692011-02-19 12:06:00 -03007160
Brian Gix604086b2011-11-23 08:28:33 -08007161int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007162 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007163{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007164 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007165 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007166}
7167
Johan Hedberg272d90d2012-02-09 15:26:12 +02007168int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007169 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007170{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007171 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007172 status,
7173 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007174}
7175
Johan Hedberg92a25252012-09-06 18:39:26 +03007176int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7177 u8 link_type, u8 addr_type, u32 passkey,
7178 u8 entered)
7179{
7180 struct mgmt_ev_passkey_notify ev;
7181
7182 BT_DBG("%s", hdev->name);
7183
7184 bacpy(&ev.addr.bdaddr, bdaddr);
7185 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7186 ev.passkey = __cpu_to_le32(passkey);
7187 ev.entered = entered;
7188
7189 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7190}
7191
Johan Hedberge1e930f2014-09-08 17:09:49 -07007192void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007193{
7194 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007195 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007196 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007197
Johan Hedberge1e930f2014-09-08 17:09:49 -07007198 bacpy(&ev.addr.bdaddr, &conn->dst);
7199 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7200 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007201
Johan Hedberge1e930f2014-09-08 17:09:49 -07007202 cmd = find_pairing(conn);
7203
7204 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7205 cmd ? cmd->sk : NULL);
7206
Johan Hedberga511b352014-12-11 21:45:45 +02007207 if (cmd) {
7208 cmd->cmd_complete(cmd, status);
7209 mgmt_pending_remove(cmd);
7210 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007211}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007212
Marcel Holtmann464996a2013-10-15 14:26:24 -07007213void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007214{
7215 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007216 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007217
7218 if (status) {
7219 u8 mgmt_err = mgmt_status(status);
7220 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007221 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007222 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007223 }
7224
Marcel Holtmann464996a2013-10-15 14:26:24 -07007225 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007226 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007227 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007228 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007229
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007230 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007231 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007232
Johan Hedberg47990ea2012-02-22 11:58:37 +02007233 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007234 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007235
7236 if (match.sk)
7237 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007238}
7239
Johan Hedberg890ea892013-03-15 17:06:52 -05007240static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007241{
Johan Hedberg890ea892013-03-15 17:06:52 -05007242 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007243 struct hci_cp_write_eir cp;
7244
Johan Hedberg976eb202012-10-24 21:12:01 +03007245 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007246 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007247
Johan Hedbergc80da272012-02-22 15:38:48 +02007248 memset(hdev->eir, 0, sizeof(hdev->eir));
7249
Johan Hedbergcacaf522012-02-21 00:52:42 +02007250 memset(&cp, 0, sizeof(cp));
7251
Johan Hedberg890ea892013-03-15 17:06:52 -05007252 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007253}
7254
Marcel Holtmann3e248562013-10-15 14:26:25 -07007255void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007256{
7257 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007258 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007259 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007260
7261 if (status) {
7262 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007263
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007264 if (enable && hci_dev_test_and_clear_flag(hdev,
7265 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007266 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007267 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007268 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007269
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007270 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7271 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007272 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007273 }
7274
7275 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007276 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007277 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007278 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007279 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007280 changed = hci_dev_test_and_clear_flag(hdev,
7281 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007282 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007283 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007284 }
7285
7286 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7287
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007288 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007289 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007290
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007291 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007292 sock_put(match.sk);
7293
Johan Hedberg890ea892013-03-15 17:06:52 -05007294 hci_req_init(&req, hdev);
7295
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007296 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7297 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007298 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7299 sizeof(enable), &enable);
Johan Hedberg890ea892013-03-15 17:06:52 -05007300 update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007301 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007302 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007303 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007304
7305 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007306}
7307
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007308static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007309{
7310 struct cmd_lookup *match = data;
7311
Johan Hedberg90e70452012-02-23 23:09:40 +02007312 if (match->sk == NULL) {
7313 match->sk = cmd->sk;
7314 sock_hold(match->sk);
7315 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007316}
7317
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007318void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7319 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007320{
Johan Hedberg90e70452012-02-23 23:09:40 +02007321 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007322
Johan Hedberg92da6092013-03-15 17:06:55 -05007323 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7324 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7325 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007326
7327 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007328 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
7329 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02007330
7331 if (match.sk)
7332 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007333}
7334
Marcel Holtmann7667da32013-10-15 14:26:27 -07007335void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007336{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007337 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007338 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007339
Johan Hedberg13928972013-03-15 17:07:00 -05007340 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007341 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007342
7343 memset(&ev, 0, sizeof(ev));
7344 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007345 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007346
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007347 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007348 if (!cmd) {
7349 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007350
Johan Hedberg13928972013-03-15 17:07:00 -05007351 /* If this is a HCI command related to powering on the
7352 * HCI dev don't send any mgmt signals.
7353 */
7354 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007355 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007356 }
7357
Marcel Holtmann7667da32013-10-15 14:26:27 -07007358 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7359 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007360}
Szymon Jancc35938b2011-03-22 13:12:21 +01007361
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007362void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
Johan Hedberg38da1702014-11-17 20:52:20 +02007363 u8 *rand192, u8 *hash256, u8 *rand256,
7364 u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01007365{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007366 struct mgmt_pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01007367
Johan Hedberg744cf192011-11-08 20:40:14 +02007368 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01007369
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007370 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01007371 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07007372 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01007373
7374 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02007375 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
7376 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01007377 } else {
Johan Hedberg66f096f2015-02-02 13:23:42 +02007378 struct mgmt_rp_read_local_oob_data rp;
7379 size_t rp_size = sizeof(rp);
7380
7381 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
7382 memcpy(rp.rand192, rand192, sizeof(rp.rand192));
7383
Johan Hedberg710f11c2014-05-26 11:21:22 +03007384 if (bredr_sc_enabled(hdev) && hash256 && rand256) {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007385 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
Johan Hedberg38da1702014-11-17 20:52:20 +02007386 memcpy(rp.rand256, rand256, sizeof(rp.rand256));
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007387 } else {
Johan Hedberg66f096f2015-02-02 13:23:42 +02007388 rp_size -= sizeof(rp.hash256) + sizeof(rp.rand256);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007389 }
Johan Hedberg66f096f2015-02-02 13:23:42 +02007390
Johan Hedberg2a1afb52015-03-06 21:08:54 +02007391 mgmt_cmd_complete(cmd->sk, hdev->id,
7392 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
7393 &rp, rp_size);
Szymon Jancc35938b2011-03-22 13:12:21 +01007394 }
7395
7396 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01007397}
Johan Hedberge17acd42011-03-30 23:57:16 +03007398
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007399static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7400{
7401 int i;
7402
7403 for (i = 0; i < uuid_count; i++) {
7404 if (!memcmp(uuid, uuids[i], 16))
7405 return true;
7406 }
7407
7408 return false;
7409}
7410
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007411static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7412{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007413 u16 parsed = 0;
7414
7415 while (parsed < eir_len) {
7416 u8 field_len = eir[0];
7417 u8 uuid[16];
7418 int i;
7419
7420 if (field_len == 0)
7421 break;
7422
7423 if (eir_len - parsed < field_len + 1)
7424 break;
7425
7426 switch (eir[1]) {
7427 case EIR_UUID16_ALL:
7428 case EIR_UUID16_SOME:
7429 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007430 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007431 uuid[13] = eir[i + 3];
7432 uuid[12] = eir[i + 2];
7433 if (has_uuid(uuid, uuid_count, uuids))
7434 return true;
7435 }
7436 break;
7437 case EIR_UUID32_ALL:
7438 case EIR_UUID32_SOME:
7439 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007440 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007441 uuid[15] = eir[i + 5];
7442 uuid[14] = eir[i + 4];
7443 uuid[13] = eir[i + 3];
7444 uuid[12] = eir[i + 2];
7445 if (has_uuid(uuid, uuid_count, uuids))
7446 return true;
7447 }
7448 break;
7449 case EIR_UUID128_ALL:
7450 case EIR_UUID128_SOME:
7451 for (i = 0; i + 17 <= field_len; i += 16) {
7452 memcpy(uuid, eir + i + 2, 16);
7453 if (has_uuid(uuid, uuid_count, uuids))
7454 return true;
7455 }
7456 break;
7457 }
7458
7459 parsed += field_len + 1;
7460 eir += field_len + 1;
7461 }
7462
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007463 return false;
7464}
7465
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007466static void restart_le_scan(struct hci_dev *hdev)
7467{
7468 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007469 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007470 return;
7471
7472 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7473 hdev->discovery.scan_start +
7474 hdev->discovery.scan_duration))
7475 return;
7476
7477 queue_delayed_work(hdev->workqueue, &hdev->le_scan_restart,
7478 DISCOV_LE_RESTART_DELAY);
7479}
7480
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007481static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7482 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7483{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007484 /* If a RSSI threshold has been specified, and
7485 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7486 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7487 * is set, let it through for further processing, as we might need to
7488 * restart the scan.
7489 *
7490 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7491 * the results are also dropped.
7492 */
7493 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7494 (rssi == HCI_RSSI_INVALID ||
7495 (rssi < hdev->discovery.rssi &&
7496 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7497 return false;
7498
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007499 if (hdev->discovery.uuid_count != 0) {
7500 /* If a list of UUIDs is provided in filter, results with no
7501 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007502 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007503 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7504 hdev->discovery.uuids) &&
7505 !eir_has_uuids(scan_rsp, scan_rsp_len,
7506 hdev->discovery.uuid_count,
7507 hdev->discovery.uuids))
7508 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007509 }
7510
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007511 /* If duplicate filtering does not report RSSI changes, then restart
7512 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007513 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007514 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7515 restart_le_scan(hdev);
7516
7517 /* Validate RSSI value against the RSSI threshold once more. */
7518 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7519 rssi < hdev->discovery.rssi)
7520 return false;
7521 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007522
7523 return true;
7524}
7525
Marcel Holtmann901801b2013-10-06 23:55:51 -07007526void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007527 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7528 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007529{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007530 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007531 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007532 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007533
Johan Hedberg75ce2082014-07-02 22:42:01 +03007534 /* Don't send events for a non-kernel initiated discovery. With
7535 * LE one exception is if we have pend_le_reports > 0 in which
7536 * case we're doing passive scanning and want these events.
7537 */
7538 if (!hci_discovery_active(hdev)) {
7539 if (link_type == ACL_LINK)
7540 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007541 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007542 return;
7543 }
Andre Guedes12602d02013-04-30 15:29:40 -03007544
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007545 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007546 /* We are using service discovery */
7547 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7548 scan_rsp_len))
7549 return;
7550 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007551
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007552 /* Make sure that the buffer is big enough. The 5 extra bytes
7553 * are for the potential CoD field.
7554 */
7555 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007556 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007557
Johan Hedberg1dc06092012-01-15 21:01:23 +02007558 memset(buf, 0, sizeof(buf));
7559
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007560 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7561 * RSSI value was reported as 0 when not available. This behavior
7562 * is kept when using device discovery. This is required for full
7563 * backwards compatibility with the API.
7564 *
7565 * However when using service discovery, the value 127 will be
7566 * returned when the RSSI is not available.
7567 */
Szymon Janc91200e92015-01-22 16:57:05 +01007568 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7569 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007570 rssi = 0;
7571
Johan Hedberg841c5642014-07-07 12:45:54 +03007572 bacpy(&ev->addr.bdaddr, bdaddr);
7573 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007574 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007575 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007576
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007577 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007578 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007579 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007580
Johan Hedberg1dc06092012-01-15 21:01:23 +02007581 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
7582 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007583 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007584
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007585 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007586 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007587 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007588
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007589 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7590 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007591
Marcel Holtmann901801b2013-10-06 23:55:51 -07007592 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007593}
Johan Hedberga88a9652011-03-30 13:18:12 +03007594
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007595void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7596 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007597{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007598 struct mgmt_ev_device_found *ev;
7599 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7600 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007601
Johan Hedbergb644ba32012-01-17 21:48:47 +02007602 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007603
Johan Hedbergb644ba32012-01-17 21:48:47 +02007604 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007605
Johan Hedbergb644ba32012-01-17 21:48:47 +02007606 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007607 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007608 ev->rssi = rssi;
7609
7610 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007611 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007612
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007613 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007614
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007615 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007616}
Johan Hedberg314b2382011-04-27 10:29:57 -04007617
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007618void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007619{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007620 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007621
Andre Guedes343fb142011-11-22 17:14:19 -03007622 BT_DBG("%s discovering %u", hdev->name, discovering);
7623
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007624 memset(&ev, 0, sizeof(ev));
7625 ev.type = hdev->discovery.type;
7626 ev.discovering = discovering;
7627
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007628 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007629}
Antti Julku5e762442011-08-25 16:48:02 +03007630
Marcel Holtmann1904a852015-01-11 13:50:44 -08007631static void adv_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Marcel Holtmann5976e602013-10-06 04:08:14 -07007632{
7633 BT_DBG("%s status %u", hdev->name, status);
Marcel Holtmann5976e602013-10-06 04:08:14 -07007634}
7635
7636void mgmt_reenable_advertising(struct hci_dev *hdev)
7637{
7638 struct hci_request req;
7639
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007640 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Marcel Holtmann5976e602013-10-06 04:08:14 -07007641 return;
7642
7643 hci_req_init(&req, hdev);
7644 enable_advertising(&req);
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03007645 hci_req_run(&req, adv_enable_complete);
Marcel Holtmann5976e602013-10-06 04:08:14 -07007646}
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007647
7648static struct hci_mgmt_chan chan = {
7649 .channel = HCI_CHANNEL_CONTROL,
7650 .handler_count = ARRAY_SIZE(mgmt_handlers),
7651 .handlers = mgmt_handlers,
7652};
7653
7654int mgmt_init(void)
7655{
7656 return hci_mgmt_chan_register(&chan);
7657}
7658
7659void mgmt_exit(void)
7660{
7661 hci_mgmt_chan_unregister(&chan);
7662}