blob: 72e41d29e3013c30e7a15a7e94d1391bcdd79b35 [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 Holtmann4f0f1552015-03-14 22:43:19 -070099 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann96f14742015-03-14 19:27:57 -0700100 MGMT_OP_READ_EXT_INDEX_LIST,
Marcel Holtmannd3d53052015-03-14 20:53:25 -0700101 MGMT_OP_READ_ADV_FEATURES,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200102};
103
104static const u16 mgmt_events[] = {
105 MGMT_EV_CONTROLLER_ERROR,
106 MGMT_EV_INDEX_ADDED,
107 MGMT_EV_INDEX_REMOVED,
108 MGMT_EV_NEW_SETTINGS,
109 MGMT_EV_CLASS_OF_DEV_CHANGED,
110 MGMT_EV_LOCAL_NAME_CHANGED,
111 MGMT_EV_NEW_LINK_KEY,
112 MGMT_EV_NEW_LONG_TERM_KEY,
113 MGMT_EV_DEVICE_CONNECTED,
114 MGMT_EV_DEVICE_DISCONNECTED,
115 MGMT_EV_CONNECT_FAILED,
116 MGMT_EV_PIN_CODE_REQUEST,
117 MGMT_EV_USER_CONFIRM_REQUEST,
118 MGMT_EV_USER_PASSKEY_REQUEST,
119 MGMT_EV_AUTH_FAILED,
120 MGMT_EV_DEVICE_FOUND,
121 MGMT_EV_DISCOVERING,
122 MGMT_EV_DEVICE_BLOCKED,
123 MGMT_EV_DEVICE_UNBLOCKED,
124 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300125 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800126 MGMT_EV_NEW_IRK,
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -0700127 MGMT_EV_NEW_CSRK,
Marcel Holtmann8afef092014-06-29 22:28:34 +0200128 MGMT_EV_DEVICE_ADDED,
129 MGMT_EV_DEVICE_REMOVED,
Andre Guedesffb5a8272014-07-01 18:10:11 -0300130 MGMT_EV_NEW_CONN_PARAM,
Marcel Holtmann0602a8a2014-07-02 21:30:54 +0200131 MGMT_EV_UNCONF_INDEX_ADDED,
Marcel Holtmannedd38962014-07-02 21:30:55 +0200132 MGMT_EV_UNCONF_INDEX_REMOVED,
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200133 MGMT_EV_NEW_CONFIG_OPTIONS,
Marcel Holtmannced85542015-03-14 19:27:56 -0700134 MGMT_EV_EXT_INDEX_ADDED,
135 MGMT_EV_EXT_INDEX_REMOVED,
Marcel Holtmann72000df2015-03-16 16:11:21 -0700136 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200137};
138
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800139#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200140
Johan Hedbergd25b78e2015-01-27 12:55:52 +0200141#define ZERO_KEY "\x00\x00\x00\x00\x00\x00\x00\x00" \
142 "\x00\x00\x00\x00\x00\x00\x00\x00"
143
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200144struct mgmt_pending_cmd {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200145 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200146 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200147 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100148 void *param;
Johan Hedberg323b0b82014-12-05 13:36:01 +0200149 size_t param_len;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200150 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300151 void *user_data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200152 int (*cmd_complete)(struct mgmt_pending_cmd *cmd, u8 status);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200153};
154
Johan Hedbergca69b792011-11-11 18:10:00 +0200155/* HCI to MGMT error code conversion table */
156static u8 mgmt_status_table[] = {
157 MGMT_STATUS_SUCCESS,
158 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
159 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
160 MGMT_STATUS_FAILED, /* Hardware Failure */
161 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
162 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200163 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200164 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
165 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
166 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
167 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
168 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
169 MGMT_STATUS_BUSY, /* Command Disallowed */
170 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
171 MGMT_STATUS_REJECTED, /* Rejected Security */
172 MGMT_STATUS_REJECTED, /* Rejected Personal */
173 MGMT_STATUS_TIMEOUT, /* Host Timeout */
174 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
175 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
176 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
177 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
178 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
179 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
180 MGMT_STATUS_BUSY, /* Repeated Attempts */
181 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
182 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
183 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
184 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
185 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
186 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
187 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
188 MGMT_STATUS_FAILED, /* Unspecified Error */
189 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
190 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
191 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
192 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
193 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
194 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
195 MGMT_STATUS_FAILED, /* Unit Link Key Used */
196 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
197 MGMT_STATUS_TIMEOUT, /* Instant Passed */
198 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
199 MGMT_STATUS_FAILED, /* Transaction Collision */
200 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
201 MGMT_STATUS_REJECTED, /* QoS Rejected */
202 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
203 MGMT_STATUS_REJECTED, /* Insufficient Security */
204 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
205 MGMT_STATUS_BUSY, /* Role Switch Pending */
206 MGMT_STATUS_FAILED, /* Slot Violation */
207 MGMT_STATUS_FAILED, /* Role Switch Failed */
208 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
209 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
210 MGMT_STATUS_BUSY, /* Host Busy Pairing */
211 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
212 MGMT_STATUS_BUSY, /* Controller Busy */
213 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
214 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
215 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
216 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
217 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
218};
219
220static u8 mgmt_status(u8 hci_status)
221{
222 if (hci_status < ARRAY_SIZE(mgmt_status_table))
223 return mgmt_status_table[hci_status];
224
225 return MGMT_STATUS_FAILED;
226}
227
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200228static int mgmt_send_event(u16 event, struct hci_dev *hdev,
229 unsigned short channel, void *data, u16 data_len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700230 int flag, struct sock *skip_sk)
Marcel Holtmann04c60f052014-07-04 19:06:22 +0200231{
232 struct sk_buff *skb;
233 struct mgmt_hdr *hdr;
234
235 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
236 if (!skb)
237 return -ENOMEM;
238
239 hdr = (void *) skb_put(skb, sizeof(*hdr));
240 hdr->opcode = cpu_to_le16(event);
241 if (hdev)
242 hdr->index = cpu_to_le16(hdev->id);
243 else
244 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
245 hdr->len = cpu_to_le16(data_len);
246
247 if (data)
248 memcpy(skb_put(skb, data_len), data, data_len);
249
250 /* Time stamp */
251 __net_timestamp(skb);
252
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700253 hci_send_to_channel(channel, skb, flag, skip_sk);
Marcel Holtmann04c60f052014-07-04 19:06:22 +0200254 kfree_skb(skb);
255
256 return 0;
257}
258
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700259static int mgmt_index_event(u16 event, struct hci_dev *hdev, void *data,
260 u16 len, int flag)
Marcel Holtmannf9207332015-03-14 19:27:55 -0700261{
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700262 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
263 flag, NULL);
Marcel Holtmannf9207332015-03-14 19:27:55 -0700264}
265
Marcel Holtmann72000df2015-03-16 16:11:21 -0700266static int mgmt_limited_event(u16 event, struct hci_dev *hdev, void *data,
267 u16 len, int flag, struct sock *skip_sk)
268{
269 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
270 flag, skip_sk);
271}
272
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700273static int mgmt_generic_event(u16 event, struct hci_dev *hdev, void *data,
274 u16 len, struct sock *skip_sk)
275{
276 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
277 HCI_MGMT_GENERIC_EVENTS, skip_sk);
278}
279
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200280static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 len,
281 struct sock *skip_sk)
282{
283 return mgmt_send_event(event, hdev, HCI_CHANNEL_CONTROL, data, len,
Marcel Holtmannc08b1a12015-03-14 19:27:59 -0700284 HCI_SOCK_TRUSTED, skip_sk);
Johan Hedberg7a00ff42015-03-06 21:08:56 +0200285}
286
Johan Hedberga69e8372015-03-06 21:08:53 +0200287static int mgmt_cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200288{
289 struct sk_buff *skb;
290 struct mgmt_hdr *hdr;
291 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300292 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200293
Szymon Janc34eb5252011-02-28 14:10:08 +0100294 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200295
Andre Guedes790eff42012-06-07 19:05:46 -0300296 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200297 if (!skb)
298 return -ENOMEM;
299
300 hdr = (void *) skb_put(skb, sizeof(*hdr));
301
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700302 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100303 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200304 hdr->len = cpu_to_le16(sizeof(*ev));
305
306 ev = (void *) skb_put(skb, sizeof(*ev));
307 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200308 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200309
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300310 err = sock_queue_rcv_skb(sk, skb);
311 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200312 kfree_skb(skb);
313
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300314 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200315}
316
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200317static int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
318 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200319{
320 struct sk_buff *skb;
321 struct mgmt_hdr *hdr;
322 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300323 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200324
325 BT_DBG("sock %p", sk);
326
Andre Guedes790eff42012-06-07 19:05:46 -0300327 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200328 if (!skb)
329 return -ENOMEM;
330
331 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200332
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700333 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100334 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200335 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200336
Johan Hedberga38528f2011-01-22 06:46:43 +0200337 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200338 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200339 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100340
341 if (rp)
342 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200343
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300344 err = sock_queue_rcv_skb(sk, skb);
345 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200346 kfree_skb(skb);
347
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100348 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200349}
350
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300351static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
352 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200353{
354 struct mgmt_rp_read_version rp;
355
356 BT_DBG("sock %p", sk);
357
358 rp.version = MGMT_VERSION;
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700359 rp.revision = cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200360
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200361 return mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0,
362 &rp, sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200363}
364
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300365static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
366 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200367{
368 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200369 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
370 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200371 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200372 size_t rp_size;
373 int i, err;
374
375 BT_DBG("sock %p", sk);
376
377 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
378
379 rp = kmalloc(rp_size, GFP_KERNEL);
380 if (!rp)
381 return -ENOMEM;
382
Joe Perchesdcf4adb2014-03-12 10:52:35 -0700383 rp->num_commands = cpu_to_le16(num_commands);
384 rp->num_events = cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200385
386 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
387 put_unaligned_le16(mgmt_commands[i], opcode);
388
389 for (i = 0; i < num_events; i++, opcode++)
390 put_unaligned_le16(mgmt_events[i], opcode);
391
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200392 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0,
393 rp, rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200394 kfree(rp);
395
396 return err;
397}
398
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300399static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
400 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200401{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200402 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200403 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200404 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200405 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300406 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200407
408 BT_DBG("sock %p", sk);
409
410 read_lock(&hci_dev_list_lock);
411
412 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300413 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200414 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700415 !hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann1514b892013-10-06 08:25:01 -0700416 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200417 }
418
Johan Hedberga38528f2011-01-22 06:46:43 +0200419 rp_len = sizeof(*rp) + (2 * count);
420 rp = kmalloc(rp_len, GFP_ATOMIC);
421 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100422 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200423 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100424 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200425
Johan Hedberg476e44c2012-10-19 20:10:46 +0300426 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200427 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700428 if (hci_dev_test_flag(d, HCI_SETUP) ||
429 hci_dev_test_flag(d, HCI_CONFIG) ||
430 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200431 continue;
432
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200433 /* Devices marked as raw-only are neither configured
434 * nor unconfigured controllers.
435 */
436 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700437 continue;
438
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200439 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700440 !hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700441 rp->index[count++] = cpu_to_le16(d->id);
442 BT_DBG("Added hci%u", d->id);
443 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200444 }
445
Johan Hedberg476e44c2012-10-19 20:10:46 +0300446 rp->num_controllers = cpu_to_le16(count);
447 rp_len = sizeof(*rp) + (2 * count);
448
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200449 read_unlock(&hci_dev_list_lock);
450
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200451 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST,
452 0, rp, rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200453
Johan Hedberga38528f2011-01-22 06:46:43 +0200454 kfree(rp);
455
456 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200457}
458
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200459static int read_unconf_index_list(struct sock *sk, struct hci_dev *hdev,
460 void *data, u16 data_len)
461{
462 struct mgmt_rp_read_unconf_index_list *rp;
463 struct hci_dev *d;
464 size_t rp_len;
465 u16 count;
466 int err;
467
468 BT_DBG("sock %p", sk);
469
470 read_lock(&hci_dev_list_lock);
471
472 count = 0;
473 list_for_each_entry(d, &hci_dev_list, list) {
474 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700475 hci_dev_test_flag(d, HCI_UNCONFIGURED))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200476 count++;
477 }
478
479 rp_len = sizeof(*rp) + (2 * count);
480 rp = kmalloc(rp_len, GFP_ATOMIC);
481 if (!rp) {
482 read_unlock(&hci_dev_list_lock);
483 return -ENOMEM;
484 }
485
486 count = 0;
487 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700488 if (hci_dev_test_flag(d, HCI_SETUP) ||
489 hci_dev_test_flag(d, HCI_CONFIG) ||
490 hci_dev_test_flag(d, HCI_USER_CHANNEL))
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200491 continue;
492
493 /* Devices marked as raw-only are neither configured
494 * nor unconfigured controllers.
495 */
496 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
497 continue;
498
499 if (d->dev_type == HCI_BREDR &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700500 hci_dev_test_flag(d, HCI_UNCONFIGURED)) {
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200501 rp->index[count++] = cpu_to_le16(d->id);
502 BT_DBG("Added hci%u", d->id);
503 }
504 }
505
506 rp->num_controllers = cpu_to_le16(count);
507 rp_len = sizeof(*rp) + (2 * count);
508
509 read_unlock(&hci_dev_list_lock);
510
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200511 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
512 MGMT_OP_READ_UNCONF_INDEX_LIST, 0, rp, rp_len);
Marcel Holtmann73d1df22014-07-02 22:10:52 +0200513
514 kfree(rp);
515
516 return err;
517}
518
Marcel Holtmann96f14742015-03-14 19:27:57 -0700519static int read_ext_index_list(struct sock *sk, struct hci_dev *hdev,
520 void *data, u16 data_len)
521{
522 struct mgmt_rp_read_ext_index_list *rp;
523 struct hci_dev *d;
524 size_t rp_len;
525 u16 count;
526 int err;
527
528 BT_DBG("sock %p", sk);
529
530 read_lock(&hci_dev_list_lock);
531
532 count = 0;
533 list_for_each_entry(d, &hci_dev_list, list) {
534 if (d->dev_type == HCI_BREDR || d->dev_type == HCI_AMP)
535 count++;
536 }
537
538 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
539 rp = kmalloc(rp_len, GFP_ATOMIC);
540 if (!rp) {
541 read_unlock(&hci_dev_list_lock);
542 return -ENOMEM;
543 }
544
545 count = 0;
546 list_for_each_entry(d, &hci_dev_list, list) {
547 if (hci_dev_test_flag(d, HCI_SETUP) ||
548 hci_dev_test_flag(d, HCI_CONFIG) ||
549 hci_dev_test_flag(d, HCI_USER_CHANNEL))
550 continue;
551
552 /* Devices marked as raw-only are neither configured
553 * nor unconfigured controllers.
554 */
555 if (test_bit(HCI_QUIRK_RAW_DEVICE, &d->quirks))
556 continue;
557
558 if (d->dev_type == HCI_BREDR) {
559 if (hci_dev_test_flag(d, HCI_UNCONFIGURED))
560 rp->entry[count].type = 0x01;
561 else
562 rp->entry[count].type = 0x00;
563 } else if (d->dev_type == HCI_AMP) {
564 rp->entry[count].type = 0x02;
565 } else {
566 continue;
567 }
568
569 rp->entry[count].bus = d->bus;
570 rp->entry[count++].index = cpu_to_le16(d->id);
571 BT_DBG("Added hci%u", d->id);
572 }
573
574 rp->num_controllers = cpu_to_le16(count);
575 rp_len = sizeof(*rp) + (sizeof(rp->entry[0]) * count);
576
577 read_unlock(&hci_dev_list_lock);
578
579 /* If this command is called at least once, then all the
580 * default index and unconfigured index events are disabled
581 * and from now on only extended index events are used.
582 */
583 hci_sock_set_flag(sk, HCI_MGMT_EXT_INDEX_EVENTS);
584 hci_sock_clear_flag(sk, HCI_MGMT_INDEX_EVENTS);
585 hci_sock_clear_flag(sk, HCI_MGMT_UNCONF_INDEX_EVENTS);
586
587 err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE,
588 MGMT_OP_READ_EXT_INDEX_LIST, 0, rp, rp_len);
589
590 kfree(rp);
591
592 return err;
593}
594
Marcel Holtmanndbece372014-07-04 18:11:55 +0200595static bool is_configured(struct hci_dev *hdev)
596{
597 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700598 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanndbece372014-07-04 18:11:55 +0200599 return false;
600
601 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
602 !bacmp(&hdev->public_addr, BDADDR_ANY))
603 return false;
604
605 return true;
606}
607
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200608static __le32 get_missing_options(struct hci_dev *hdev)
609{
610 u32 options = 0;
611
Marcel Holtmanndbece372014-07-04 18:11:55 +0200612 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700613 !hci_dev_test_flag(hdev, HCI_EXT_CONFIGURED))
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200614 options |= MGMT_OPTION_EXTERNAL_CONFIG;
615
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200616 if (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) &&
617 !bacmp(&hdev->public_addr, BDADDR_ANY))
618 options |= MGMT_OPTION_PUBLIC_ADDRESS;
619
620 return cpu_to_le32(options);
621}
622
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200623static int new_options(struct hci_dev *hdev, struct sock *skip)
624{
625 __le32 options = get_missing_options(hdev);
626
Marcel Holtmannf6b77122015-03-14 19:28:05 -0700627 return mgmt_generic_event(MGMT_EV_NEW_CONFIG_OPTIONS, hdev, &options,
628 sizeof(options), skip);
Marcel Holtmannf4537c02014-07-04 19:06:23 +0200629}
630
Marcel Holtmanndbece372014-07-04 18:11:55 +0200631static int send_options_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
632{
633 __le32 options = get_missing_options(hdev);
634
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200635 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &options,
636 sizeof(options));
Marcel Holtmanndbece372014-07-04 18:11:55 +0200637}
638
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200639static int read_config_info(struct sock *sk, struct hci_dev *hdev,
640 void *data, u16 data_len)
641{
642 struct mgmt_rp_read_config_info rp;
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200643 u32 options = 0;
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200644
645 BT_DBG("sock %p %s", sk, hdev->name);
646
647 hci_dev_lock(hdev);
648
649 memset(&rp, 0, sizeof(rp));
650 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200651
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200652 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
653 options |= MGMT_OPTION_EXTERNAL_CONFIG;
654
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200655 if (hdev->set_bdaddr)
Marcel Holtmann89bc22d2014-07-04 16:54:37 +0200656 options |= MGMT_OPTION_PUBLIC_ADDRESS;
657
658 rp.supported_options = cpu_to_le32(options);
659 rp.missing_options = get_missing_options(hdev);
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200660
661 hci_dev_unlock(hdev);
662
Johan Hedberg2a1afb52015-03-06 21:08:54 +0200663 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_CONFIG_INFO, 0,
664 &rp, sizeof(rp));
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200665}
666
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200667static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200668{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200669 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200670
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200671 settings |= MGMT_SETTING_POWERED;
Johan Hedbergb2939472014-07-30 09:22:23 +0300672 settings |= MGMT_SETTING_BONDABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800673 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg3742abf2014-07-08 16:07:34 +0300674 settings |= MGMT_SETTING_CONNECTABLE;
675 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200676
Andre Guedesed3fa312012-07-24 15:03:46 -0300677 if (lmp_bredr_capable(hdev)) {
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500678 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
679 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200680 settings |= MGMT_SETTING_BREDR;
681 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700682
683 if (lmp_ssp_capable(hdev)) {
684 settings |= MGMT_SETTING_SSP;
685 settings |= MGMT_SETTING_HS;
686 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800687
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -0800688 if (lmp_sc_capable(hdev))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800689 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700690 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100691
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300692 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200693 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300694 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberga3209692014-05-26 11:23:35 +0300695 settings |= MGMT_SETTING_SECURE_CONN;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200696 settings |= MGMT_SETTING_PRIVACY;
Marcel Holtmann93690c22015-03-06 10:11:21 -0800697 settings |= MGMT_SETTING_STATIC_ADDRESS;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300698 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200699
Marcel Holtmanneb1904f2014-07-04 17:23:33 +0200700 if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) ||
701 hdev->set_bdaddr)
Marcel Holtmann9fc3bfb2014-07-04 00:46:56 +0200702 settings |= MGMT_SETTING_CONFIGURATION;
703
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200704 return settings;
705}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200706
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200707static u32 get_current_settings(struct hci_dev *hdev)
708{
709 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200710
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200711 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100712 settings |= MGMT_SETTING_POWERED;
713
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700714 if (hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200715 settings |= MGMT_SETTING_CONNECTABLE;
716
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700717 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500718 settings |= MGMT_SETTING_FAST_CONNECTABLE;
719
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700720 if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200721 settings |= MGMT_SETTING_DISCOVERABLE;
722
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700723 if (hci_dev_test_flag(hdev, HCI_BONDABLE))
Johan Hedbergb2939472014-07-30 09:22:23 +0300724 settings |= MGMT_SETTING_BONDABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200725
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700726 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200727 settings |= MGMT_SETTING_BREDR;
728
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700729 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200730 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200731
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700732 if (hci_dev_test_flag(hdev, HCI_LINK_SECURITY))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200733 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200734
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700735 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200736 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200737
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700738 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200739 settings |= MGMT_SETTING_HS;
740
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700741 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300742 settings |= MGMT_SETTING_ADVERTISING;
743
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700744 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800745 settings |= MGMT_SETTING_SECURE_CONN;
746
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700747 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800748 settings |= MGMT_SETTING_DEBUG_KEYS;
749
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700750 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200751 settings |= MGMT_SETTING_PRIVACY;
752
Marcel Holtmann93690c22015-03-06 10:11:21 -0800753 /* The current setting for static address has two purposes. The
754 * first is to indicate if the static address will be used and
755 * the second is to indicate if it is actually set.
756 *
757 * This means if the static address is not configured, this flag
758 * will never bet set. If the address is configured, then if the
759 * address is actually used decides if the flag is set or not.
760 *
761 * For single mode LE only controllers and dual-mode controllers
762 * with BR/EDR disabled, the existence of the static address will
763 * be evaluated.
764 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700765 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700766 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800767 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
768 if (bacmp(&hdev->static_addr, BDADDR_ANY))
769 settings |= MGMT_SETTING_STATIC_ADDRESS;
770 }
771
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200772 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200773}
774
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300775#define PNP_INFO_SVCLASS_ID 0x1200
776
Johan Hedberg213202e2013-01-27 00:31:33 +0200777static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
778{
779 u8 *ptr = data, *uuids_start = NULL;
780 struct bt_uuid *uuid;
781
782 if (len < 4)
783 return ptr;
784
785 list_for_each_entry(uuid, &hdev->uuids, list) {
786 u16 uuid16;
787
788 if (uuid->size != 16)
789 continue;
790
791 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
792 if (uuid16 < 0x1100)
793 continue;
794
795 if (uuid16 == PNP_INFO_SVCLASS_ID)
796 continue;
797
798 if (!uuids_start) {
799 uuids_start = ptr;
800 uuids_start[0] = 1;
801 uuids_start[1] = EIR_UUID16_ALL;
802 ptr += 2;
803 }
804
805 /* Stop if not enough space to put next UUID */
806 if ((ptr - data) + sizeof(u16) > len) {
807 uuids_start[1] = EIR_UUID16_SOME;
808 break;
809 }
810
811 *ptr++ = (uuid16 & 0x00ff);
812 *ptr++ = (uuid16 & 0xff00) >> 8;
813 uuids_start[0] += sizeof(uuid16);
814 }
815
816 return ptr;
817}
818
Johan Hedbergcdf19632013-01-27 00:31:34 +0200819static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
820{
821 u8 *ptr = data, *uuids_start = NULL;
822 struct bt_uuid *uuid;
823
824 if (len < 6)
825 return ptr;
826
827 list_for_each_entry(uuid, &hdev->uuids, list) {
828 if (uuid->size != 32)
829 continue;
830
831 if (!uuids_start) {
832 uuids_start = ptr;
833 uuids_start[0] = 1;
834 uuids_start[1] = EIR_UUID32_ALL;
835 ptr += 2;
836 }
837
838 /* Stop if not enough space to put next UUID */
839 if ((ptr - data) + sizeof(u32) > len) {
840 uuids_start[1] = EIR_UUID32_SOME;
841 break;
842 }
843
844 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
845 ptr += sizeof(u32);
846 uuids_start[0] += sizeof(u32);
847 }
848
849 return ptr;
850}
851
Johan Hedbergc00d5752013-01-27 00:31:35 +0200852static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
853{
854 u8 *ptr = data, *uuids_start = NULL;
855 struct bt_uuid *uuid;
856
857 if (len < 18)
858 return ptr;
859
860 list_for_each_entry(uuid, &hdev->uuids, list) {
861 if (uuid->size != 128)
862 continue;
863
864 if (!uuids_start) {
865 uuids_start = ptr;
866 uuids_start[0] = 1;
867 uuids_start[1] = EIR_UUID128_ALL;
868 ptr += 2;
869 }
870
871 /* Stop if not enough space to put next UUID */
872 if ((ptr - data) + 16 > len) {
873 uuids_start[1] = EIR_UUID128_SOME;
874 break;
875 }
876
877 memcpy(ptr, uuid->uuid, 16);
878 ptr += 16;
879 uuids_start[0] += 16;
880 }
881
882 return ptr;
883}
884
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200885static struct mgmt_pending_cmd *mgmt_pending_find(u16 opcode,
886 struct hci_dev *hdev)
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300887{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200888 struct mgmt_pending_cmd *cmd;
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300889
890 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
891 if (cmd->opcode == opcode)
892 return cmd;
893 }
894
895 return NULL;
896}
897
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200898static struct mgmt_pending_cmd *mgmt_pending_find_data(u16 opcode,
899 struct hci_dev *hdev,
900 const void *data)
Johan Hedberg95868422014-06-28 17:54:07 +0300901{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200902 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +0300903
904 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
905 if (cmd->user_data != data)
906 continue;
907 if (cmd->opcode == opcode)
908 return cmd;
909 }
910
911 return NULL;
912}
913
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700914static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
915{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700916 u8 ad_len = 0;
917 size_t name_len;
918
919 name_len = strlen(hdev->dev_name);
920 if (name_len > 0) {
921 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
922
923 if (name_len > max_len) {
924 name_len = max_len;
925 ptr[1] = EIR_NAME_SHORT;
926 } else
927 ptr[1] = EIR_NAME_COMPLETE;
928
929 ptr[0] = name_len + 1;
930
931 memcpy(ptr + 2, hdev->dev_name, name_len);
932
933 ad_len += (name_len + 2);
934 ptr += (name_len + 2);
935 }
936
937 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700938}
939
940static void update_scan_rsp_data(struct hci_request *req)
941{
942 struct hci_dev *hdev = req->hdev;
943 struct hci_cp_le_set_scan_rsp_data cp;
944 u8 len;
945
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700946 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700947 return;
948
949 memset(&cp, 0, sizeof(cp));
950
951 len = create_scan_rsp_data(hdev, cp.data);
952
Johan Hedbergeb438b52013-10-16 15:31:07 +0300953 if (hdev->scan_rsp_data_len == len &&
954 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700955 return;
956
Johan Hedbergeb438b52013-10-16 15:31:07 +0300957 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
958 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700959
960 cp.length = len;
961
962 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
963}
964
Johan Hedberg9a43e252013-10-20 19:00:07 +0300965static u8 get_adv_discov_flags(struct hci_dev *hdev)
966{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200967 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300968
969 /* If there's a pending mgmt command the flags will not yet have
970 * their final values, so check for this first.
971 */
972 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
973 if (cmd) {
974 struct mgmt_mode *cp = cmd->param;
975 if (cp->val == 0x01)
976 return LE_AD_GENERAL;
977 else if (cp->val == 0x02)
978 return LE_AD_LIMITED;
979 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700980 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300981 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700982 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300983 return LE_AD_GENERAL;
984 }
985
986 return 0;
987}
988
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700989static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700990{
991 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700992
Johan Hedberg9a43e252013-10-20 19:00:07 +0300993 flags |= get_adv_discov_flags(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700994
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700995 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700996 flags |= LE_AD_NO_BREDR;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700997
998 if (flags) {
999 BT_DBG("adv flags 0x%02x", flags);
1000
1001 ptr[0] = 2;
1002 ptr[1] = EIR_FLAGS;
1003 ptr[2] = flags;
1004
1005 ad_len += 3;
1006 ptr += 3;
1007 }
1008
1009 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
1010 ptr[0] = 2;
1011 ptr[1] = EIR_TX_POWER;
1012 ptr[2] = (u8) hdev->adv_tx_power;
1013
1014 ad_len += 3;
1015 ptr += 3;
1016 }
1017
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001018 return ad_len;
1019}
1020
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001021static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001022{
1023 struct hci_dev *hdev = req->hdev;
1024 struct hci_cp_le_set_adv_data cp;
1025 u8 len;
1026
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001027 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001028 return;
1029
1030 memset(&cp, 0, sizeof(cp));
1031
Marcel Holtmann46cad2e2013-10-16 00:16:46 -07001032 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001033
1034 if (hdev->adv_data_len == len &&
1035 memcmp(cp.data, hdev->adv_data, len) == 0)
1036 return;
1037
1038 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
1039 hdev->adv_data_len = len;
1040
1041 cp.length = len;
1042
1043 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
1044}
1045
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001046int mgmt_update_adv_data(struct hci_dev *hdev)
1047{
1048 struct hci_request req;
1049
1050 hci_req_init(&req, hdev);
1051 update_adv_data(&req);
1052
1053 return hci_req_run(&req, NULL);
1054}
1055
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001056static void create_eir(struct hci_dev *hdev, u8 *data)
1057{
1058 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001059 size_t name_len;
1060
1061 name_len = strlen(hdev->dev_name);
1062
1063 if (name_len > 0) {
1064 /* EIR Data type */
1065 if (name_len > 48) {
1066 name_len = 48;
1067 ptr[1] = EIR_NAME_SHORT;
1068 } else
1069 ptr[1] = EIR_NAME_COMPLETE;
1070
1071 /* EIR Data length */
1072 ptr[0] = name_len + 1;
1073
1074 memcpy(ptr + 2, hdev->dev_name, name_len);
1075
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001076 ptr += (name_len + 2);
1077 }
1078
Johan Hedbergbbaf4442012-11-08 01:22:59 +01001079 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -07001080 ptr[0] = 2;
1081 ptr[1] = EIR_TX_POWER;
1082 ptr[2] = (u8) hdev->inq_tx_power;
1083
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -07001084 ptr += 3;
1085 }
1086
Marcel Holtmann2b9be132012-03-11 19:32:12 -07001087 if (hdev->devid_source > 0) {
1088 ptr[0] = 9;
1089 ptr[1] = EIR_DEVICE_ID;
1090
1091 put_unaligned_le16(hdev->devid_source, ptr + 2);
1092 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
1093 put_unaligned_le16(hdev->devid_product, ptr + 6);
1094 put_unaligned_le16(hdev->devid_version, ptr + 8);
1095
Marcel Holtmann2b9be132012-03-11 19:32:12 -07001096 ptr += 10;
1097 }
1098
Johan Hedberg213202e2013-01-27 00:31:33 +02001099 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +02001100 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +02001101 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001102}
1103
Johan Hedberg890ea892013-03-15 17:06:52 -05001104static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001105{
Johan Hedberg890ea892013-03-15 17:06:52 -05001106 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001107 struct hci_cp_write_eir cp;
1108
Johan Hedberg504c8dc2012-02-23 13:30:41 +02001109 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001110 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +02001111
Johan Hedberg976eb202012-10-24 21:12:01 +03001112 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001113 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001114
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001115 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg890ea892013-03-15 17:06:52 -05001116 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001117
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001118 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -05001119 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001120
1121 memset(&cp, 0, sizeof(cp));
1122
1123 create_eir(hdev, cp.data);
1124
1125 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -05001126 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001127
1128 memcpy(hdev->eir, cp.data, sizeof(cp.data));
1129
Johan Hedberg890ea892013-03-15 17:06:52 -05001130 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001131}
1132
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001133static u8 get_service_classes(struct hci_dev *hdev)
1134{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -03001135 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001136 u8 val = 0;
1137
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -03001138 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001139 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001140
1141 return val;
1142}
1143
Johan Hedberg890ea892013-03-15 17:06:52 -05001144static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001145{
Johan Hedberg890ea892013-03-15 17:06:52 -05001146 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001147 u8 cod[3];
1148
1149 BT_DBG("%s", hdev->name);
1150
Johan Hedberg504c8dc2012-02-23 13:30:41 +02001151 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001152 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +02001153
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001154 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedbergf87ea1d2013-10-19 23:38:17 +03001155 return;
1156
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001157 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -05001158 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001159
1160 cod[0] = hdev->minor_class;
1161 cod[1] = hdev->major_class;
1162 cod[2] = get_service_classes(hdev);
1163
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001164 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Marcel Holtmann6acd7db2013-10-15 06:33:53 -07001165 cod[1] |= 0x20;
1166
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001167 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -05001168 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001169
Johan Hedberg890ea892013-03-15 17:06:52 -05001170 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001171}
1172
Johan Hedberga4858cb2014-02-25 19:56:31 +02001173static bool get_connectable(struct hci_dev *hdev)
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001174{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001175 struct mgmt_pending_cmd *cmd;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001176
1177 /* If there's a pending mgmt command the flag will not yet have
1178 * it's final value, so check for this first.
1179 */
1180 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1181 if (cmd) {
1182 struct mgmt_mode *cp = cmd->param;
Johan Hedberga4858cb2014-02-25 19:56:31 +02001183 return cp->val;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001184 }
1185
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001186 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001187}
1188
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001189static void disable_advertising(struct hci_request *req)
1190{
1191 u8 enable = 0x00;
1192
1193 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1194}
1195
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001196static void enable_advertising(struct hci_request *req)
1197{
1198 struct hci_dev *hdev = req->hdev;
1199 struct hci_cp_le_set_adv_param cp;
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001200 u8 own_addr_type, enable = 0x01;
Johan Hedberga4858cb2014-02-25 19:56:31 +02001201 bool connectable;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001202
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001203 if (hci_conn_num(hdev, LE_LINK) > 0)
1204 return;
1205
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001206 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001207 disable_advertising(req);
1208
Johan Hedberg5ce194c2014-07-08 15:07:49 +03001209 /* Clear the HCI_LE_ADV bit temporarily so that the
Johan Hedberg8d972502014-02-28 12:54:14 +02001210 * hci_update_random_address knows that it's safe to go ahead
1211 * and write a new random address. The flag will be set back on
1212 * as soon as the SET_ADV_ENABLE HCI command completes.
1213 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001214 hci_dev_clear_flag(hdev, HCI_LE_ADV);
Johan Hedberg8d972502014-02-28 12:54:14 +02001215
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001216 if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07001217 connectable = true;
1218 else
1219 connectable = get_connectable(hdev);
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001220
Johan Hedberga4858cb2014-02-25 19:56:31 +02001221 /* Set require_privacy to true only when non-connectable
1222 * advertising is used. In that case it is fine to use a
1223 * non-resolvable private address.
1224 */
1225 if (hci_update_random_address(req, !connectable, &own_addr_type) < 0)
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001226 return;
1227
Marcel Holtmann41c90c12014-02-23 20:25:55 -08001228 memset(&cp, 0, sizeof(cp));
Georg Lukas628531c2014-07-26 13:59:57 +02001229 cp.min_interval = cpu_to_le16(hdev->le_adv_min_interval);
1230 cp.max_interval = cpu_to_le16(hdev->le_adv_max_interval);
Johan Hedberga4858cb2014-02-25 19:56:31 +02001231 cp.type = connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001232 cp.own_address_type = own_addr_type;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001233 cp.channel_map = hdev->le_adv_channel_map;
1234
1235 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1236
1237 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1238}
1239
Johan Hedberg7d785252011-12-15 00:47:39 +02001240static void service_cache_off(struct work_struct *work)
1241{
1242 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001243 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -05001244 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +02001245
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001246 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +02001247 return;
1248
Johan Hedberg890ea892013-03-15 17:06:52 -05001249 hci_req_init(&req, hdev);
1250
Johan Hedberg7d785252011-12-15 00:47:39 +02001251 hci_dev_lock(hdev);
1252
Johan Hedberg890ea892013-03-15 17:06:52 -05001253 update_eir(&req);
1254 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001255
1256 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001257
1258 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +02001259}
1260
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001261static void rpa_expired(struct work_struct *work)
1262{
1263 struct hci_dev *hdev = container_of(work, struct hci_dev,
1264 rpa_expired.work);
1265 struct hci_request req;
1266
1267 BT_DBG("");
1268
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001269 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001270
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001271 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001272 return;
1273
1274 /* The generation of a new RPA and programming it into the
1275 * controller happens in the enable_advertising() function.
1276 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001277 hci_req_init(&req, hdev);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001278 enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001279 hci_req_run(&req, NULL);
1280}
1281
Johan Hedberg6a919082012-02-28 06:17:26 +02001282static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +02001283{
Marcel Holtmann238be782015-03-13 02:11:06 -07001284 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +02001285 return;
1286
Johan Hedberg4f87da82012-03-02 19:55:56 +02001287 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001288 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +02001289
Johan Hedberg4f87da82012-03-02 19:55:56 +02001290 /* Non-mgmt controlled devices get this bit set
1291 * implicitly so that pairing works for them, however
1292 * for mgmt we require user-space to explicitly enable
1293 * it
1294 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001295 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +02001296}
1297
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001298static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001299 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001300{
1301 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001302
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001303 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001304
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001305 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001306
Johan Hedberg03811012010-12-08 00:21:06 +02001307 memset(&rp, 0, sizeof(rp));
1308
Johan Hedberg03811012010-12-08 00:21:06 +02001309 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001310
1311 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001312 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001313
1314 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1315 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1316
1317 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +02001318
1319 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001320 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +02001321
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001322 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001323
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001324 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1325 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +02001326}
1327
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001328static void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
Johan Hedberg03811012010-12-08 00:21:06 +02001329{
1330 sock_put(cmd->sk);
1331 kfree(cmd->param);
1332 kfree(cmd);
1333}
1334
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001335static struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
1336 struct hci_dev *hdev,
1337 void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001338{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001339 struct mgmt_pending_cmd *cmd;
Johan Hedberg03811012010-12-08 00:21:06 +02001340
Johan Hedbergfca20012014-06-28 17:54:05 +03001341 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001342 if (!cmd)
1343 return NULL;
1344
1345 cmd->opcode = opcode;
1346 cmd->index = hdev->id;
1347
Johan Hedberg323b0b82014-12-05 13:36:01 +02001348 cmd->param = kmemdup(data, len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001349 if (!cmd->param) {
1350 kfree(cmd);
1351 return NULL;
1352 }
1353
Johan Hedberg323b0b82014-12-05 13:36:01 +02001354 cmd->param_len = len;
Johan Hedberg03811012010-12-08 00:21:06 +02001355
1356 cmd->sk = sk;
1357 sock_hold(sk);
1358
1359 list_add(&cmd->list, &hdev->mgmt_pending);
1360
1361 return cmd;
1362}
1363
1364static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001365 void (*cb)(struct mgmt_pending_cmd *cmd,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001366 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001367 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02001368{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001369 struct mgmt_pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +02001370
Andre Guedesa3d09352013-02-01 11:21:30 -03001371 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +02001372 if (opcode > 0 && cmd->opcode != opcode)
1373 continue;
1374
1375 cb(cmd, data);
1376 }
1377}
1378
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001379static void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
Johan Hedberg03811012010-12-08 00:21:06 +02001380{
1381 list_del(&cmd->list);
1382 mgmt_pending_free(cmd);
1383}
1384
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001385static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001386{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001387 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001388
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001389 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1390 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001391}
1392
Marcel Holtmann1904a852015-01-11 13:50:44 -08001393static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001394{
1395 BT_DBG("%s status 0x%02x", hdev->name, status);
1396
Johan Hedberga3172b72014-02-28 09:33:44 +02001397 if (hci_conn_count(hdev) == 0) {
1398 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001399 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001400 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001401}
1402
Johan Hedberg23a48092014-07-08 16:05:06 +03001403static bool hci_stop_discovery(struct hci_request *req)
Johan Hedberg21a60d32014-06-10 14:05:58 +03001404{
1405 struct hci_dev *hdev = req->hdev;
1406 struct hci_cp_remote_name_req_cancel cp;
1407 struct inquiry_entry *e;
1408
1409 switch (hdev->discovery.state) {
1410 case DISCOVERY_FINDING:
1411 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
1412 hci_req_add(req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
1413 } else {
1414 cancel_delayed_work(&hdev->le_scan_disable);
1415 hci_req_add_le_scan_disable(req);
1416 }
1417
Johan Hedberg23a48092014-07-08 16:05:06 +03001418 return true;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001419
1420 case DISCOVERY_RESOLVING:
1421 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
1422 NAME_PENDING);
1423 if (!e)
Johan Hedberg23a48092014-07-08 16:05:06 +03001424 break;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001425
1426 bacpy(&cp.bdaddr, &e->data.bdaddr);
1427 hci_req_add(req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
1428 &cp);
1429
Johan Hedberg23a48092014-07-08 16:05:06 +03001430 return true;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001431
1432 default:
1433 /* Passive scanning */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001434 if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
Johan Hedberg21a60d32014-06-10 14:05:58 +03001435 hci_req_add_le_scan_disable(req);
Johan Hedberg23a48092014-07-08 16:05:06 +03001436 return true;
1437 }
1438
Johan Hedberg21a60d32014-06-10 14:05:58 +03001439 break;
1440 }
Johan Hedberg23a48092014-07-08 16:05:06 +03001441
1442 return false;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001443}
1444
Johan Hedberg8b064a32014-02-24 14:52:22 +02001445static int clean_up_hci_state(struct hci_dev *hdev)
1446{
1447 struct hci_request req;
1448 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001449 bool discov_stopped;
1450 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001451
1452 hci_req_init(&req, hdev);
1453
1454 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1455 test_bit(HCI_PSCAN, &hdev->flags)) {
1456 u8 scan = 0x00;
1457 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1458 }
1459
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001460 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedberg8b064a32014-02-24 14:52:22 +02001461 disable_advertising(&req);
1462
Johan Hedberg23a48092014-07-08 16:05:06 +03001463 discov_stopped = hci_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001464
1465 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
1466 struct hci_cp_disconnect dc;
Johan Hedbergc9910d02014-02-27 14:35:12 +02001467 struct hci_cp_reject_conn_req rej;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001468
Johan Hedbergc9910d02014-02-27 14:35:12 +02001469 switch (conn->state) {
1470 case BT_CONNECTED:
1471 case BT_CONFIG:
1472 dc.handle = cpu_to_le16(conn->handle);
1473 dc.reason = 0x15; /* Terminated due to Power Off */
1474 hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1475 break;
1476 case BT_CONNECT:
1477 if (conn->type == LE_LINK)
1478 hci_req_add(&req, HCI_OP_LE_CREATE_CONN_CANCEL,
1479 0, NULL);
1480 else if (conn->type == ACL_LINK)
1481 hci_req_add(&req, HCI_OP_CREATE_CONN_CANCEL,
1482 6, &conn->dst);
1483 break;
1484 case BT_CONNECT2:
1485 bacpy(&rej.bdaddr, &conn->dst);
1486 rej.reason = 0x15; /* Terminated due to Power Off */
1487 if (conn->type == ACL_LINK)
1488 hci_req_add(&req, HCI_OP_REJECT_CONN_REQ,
1489 sizeof(rej), &rej);
1490 else if (conn->type == SCO_LINK)
1491 hci_req_add(&req, HCI_OP_REJECT_SYNC_CONN_REQ,
1492 sizeof(rej), &rej);
1493 break;
1494 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001495 }
1496
Johan Hedberg23a48092014-07-08 16:05:06 +03001497 err = hci_req_run(&req, clean_up_hci_complete);
1498 if (!err && discov_stopped)
1499 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1500
1501 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001502}
1503
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001504static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001505 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001506{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001507 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001508 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001509 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001510
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001511 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001512
Johan Hedberga7e80f22013-01-09 16:05:19 +02001513 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001514 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1515 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001516
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001517 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001518
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001519 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001520 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1521 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001522 goto failed;
1523 }
1524
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001525 if (hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001526 cancel_delayed_work(&hdev->power_off);
1527
1528 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +02001529 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
1530 data, len);
1531 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001532 goto failed;
1533 }
1534 }
1535
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001536 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001537 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001538 goto failed;
1539 }
1540
Johan Hedberg03811012010-12-08 00:21:06 +02001541 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1542 if (!cmd) {
1543 err = -ENOMEM;
1544 goto failed;
1545 }
1546
Johan Hedberg8b064a32014-02-24 14:52:22 +02001547 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001548 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001549 err = 0;
1550 } else {
1551 /* Disconnect connections, stop scans, etc */
1552 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001553 if (!err)
1554 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1555 HCI_POWER_OFF_TIMEOUT);
Johan Hedberg03811012010-12-08 00:21:06 +02001556
Johan Hedberg8b064a32014-02-24 14:52:22 +02001557 /* ENODATA means there were no HCI commands queued */
1558 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001559 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001560 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1561 err = 0;
1562 }
1563 }
Johan Hedberg03811012010-12-08 00:21:06 +02001564
1565failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001566 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001567 return err;
1568}
1569
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001570static int new_settings(struct hci_dev *hdev, struct sock *skip)
1571{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001572 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001573
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001574 return mgmt_generic_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1575 sizeof(ev), skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001576}
1577
Johan Hedberg91a668b2014-07-09 13:28:26 +03001578int mgmt_new_settings(struct hci_dev *hdev)
1579{
1580 return new_settings(hdev, NULL);
1581}
1582
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001583struct cmd_lookup {
1584 struct sock *sk;
1585 struct hci_dev *hdev;
1586 u8 mgmt_status;
1587};
1588
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001589static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001590{
1591 struct cmd_lookup *match = data;
1592
1593 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1594
1595 list_del(&cmd->list);
1596
1597 if (match->sk == NULL) {
1598 match->sk = cmd->sk;
1599 sock_hold(match->sk);
1600 }
1601
1602 mgmt_pending_free(cmd);
1603}
1604
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001605static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001606{
1607 u8 *status = data;
1608
Johan Hedberga69e8372015-03-06 21:08:53 +02001609 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001610 mgmt_pending_remove(cmd);
1611}
1612
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001613static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001614{
1615 if (cmd->cmd_complete) {
1616 u8 *status = data;
1617
1618 cmd->cmd_complete(cmd, *status);
1619 mgmt_pending_remove(cmd);
1620
1621 return;
1622 }
1623
1624 cmd_status_rsp(cmd, data);
1625}
1626
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001627static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001628{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001629 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1630 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001631}
1632
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001633static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001634{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001635 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1636 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001637}
1638
Johan Hedberge6fe7982013-10-02 15:45:22 +03001639static u8 mgmt_bredr_support(struct hci_dev *hdev)
1640{
1641 if (!lmp_bredr_capable(hdev))
1642 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001643 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001644 return MGMT_STATUS_REJECTED;
1645 else
1646 return MGMT_STATUS_SUCCESS;
1647}
1648
1649static u8 mgmt_le_support(struct hci_dev *hdev)
1650{
1651 if (!lmp_le_capable(hdev))
1652 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001653 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001654 return MGMT_STATUS_REJECTED;
1655 else
1656 return MGMT_STATUS_SUCCESS;
1657}
1658
Marcel Holtmann1904a852015-01-11 13:50:44 -08001659static void set_discoverable_complete(struct hci_dev *hdev, u8 status,
1660 u16 opcode)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001661{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001662 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001663 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001664 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001665 bool changed;
1666
1667 BT_DBG("status 0x%02x", status);
1668
1669 hci_dev_lock(hdev);
1670
1671 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1672 if (!cmd)
1673 goto unlock;
1674
1675 if (status) {
1676 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001677 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001678 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001679 goto remove_cmd;
1680 }
1681
1682 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001683 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001684 changed = !hci_dev_test_and_set_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001685
1686 if (hdev->discov_timeout > 0) {
1687 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1688 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1689 to);
1690 }
1691 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001692 changed = hci_dev_test_and_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001693 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001694
1695 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1696
1697 if (changed)
1698 new_settings(hdev, cmd->sk);
1699
Marcel Holtmann970ba522013-10-15 06:33:57 -07001700 /* When the discoverable mode gets changed, make sure
1701 * that class of device has the limited discoverable
Johan Hedberg432df052014-08-01 11:13:31 +03001702 * bit correctly set. Also update page scan based on whitelist
1703 * entries.
Marcel Holtmann970ba522013-10-15 06:33:57 -07001704 */
1705 hci_req_init(&req, hdev);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001706 __hci_update_page_scan(&req);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001707 update_class(&req);
1708 hci_req_run(&req, NULL);
1709
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001710remove_cmd:
1711 mgmt_pending_remove(cmd);
1712
1713unlock:
1714 hci_dev_unlock(hdev);
1715}
1716
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001717static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001718 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001719{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001720 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001721 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001722 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001723 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001724 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001725 int err;
Johan Hedberge41d8b42010-12-13 21:07:03 +02001726
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001727 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001728
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001729 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1730 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001731 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1732 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001733
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001734 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001735 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1736 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001737
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001738 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001739
1740 /* Disabling discoverable requires that no timeout is set,
1741 * and enabling limited discoverable requires a timeout.
1742 */
1743 if ((cp->val == 0x00 && timeout > 0) ||
1744 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001745 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1746 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001747
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001748 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001749
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001750 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001751 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1752 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001753 goto failed;
1754 }
1755
1756 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001757 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001758 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1759 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001760 goto failed;
1761 }
1762
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001763 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001764 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1765 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001766 goto failed;
1767 }
1768
1769 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001770 bool changed = false;
1771
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001772 /* Setting limited discoverable when powered off is
1773 * not a valid operation since it requires a timeout
1774 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1775 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001776 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001777 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001778 changed = true;
1779 }
1780
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001781 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001782 if (err < 0)
1783 goto failed;
1784
1785 if (changed)
1786 err = new_settings(hdev, sk);
1787
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001788 goto failed;
1789 }
1790
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001791 /* If the current mode is the same, then just update the timeout
1792 * value with the new value. And if only the timeout gets updated,
1793 * then no need for any HCI transactions.
1794 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001795 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1796 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1797 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001798 cancel_delayed_work(&hdev->discov_off);
1799 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001800
Marcel Holtmann36261542013-10-15 08:28:51 -07001801 if (cp->val && hdev->discov_timeout > 0) {
1802 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001803 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001804 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001805 }
1806
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001807 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001808 goto failed;
1809 }
1810
1811 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1812 if (!cmd) {
1813 err = -ENOMEM;
1814 goto failed;
1815 }
1816
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001817 /* Cancel any potential discoverable timeout that might be
1818 * still active and store new timeout value. The arming of
1819 * the timeout happens in the complete handler.
1820 */
1821 cancel_delayed_work(&hdev->discov_off);
1822 hdev->discov_timeout = timeout;
1823
Johan Hedbergb456f872013-10-19 23:38:22 +03001824 /* Limited discoverable mode */
1825 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001826 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001827 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001828 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001829
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001830 hci_req_init(&req, hdev);
1831
Johan Hedberg9a43e252013-10-20 19:00:07 +03001832 /* The procedure for LE-only controllers is much simpler - just
1833 * update the advertising data.
1834 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001835 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg9a43e252013-10-20 19:00:07 +03001836 goto update_ad;
1837
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001838 scan = SCAN_PAGE;
1839
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001840 if (cp->val) {
1841 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001842
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001843 if (cp->val == 0x02) {
1844 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001845 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001846 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1847 hci_cp.iac_lap[1] = 0x8b;
1848 hci_cp.iac_lap[2] = 0x9e;
1849 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1850 hci_cp.iac_lap[4] = 0x8b;
1851 hci_cp.iac_lap[5] = 0x9e;
1852 } else {
1853 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001854 hci_cp.num_iac = 1;
1855 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1856 hci_cp.iac_lap[1] = 0x8b;
1857 hci_cp.iac_lap[2] = 0x9e;
1858 }
1859
1860 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1861 (hci_cp.num_iac * 3) + 1, &hci_cp);
1862
1863 scan |= SCAN_INQUIRY;
1864 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001865 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001866 }
1867
1868 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001869
Johan Hedberg9a43e252013-10-20 19:00:07 +03001870update_ad:
1871 update_adv_data(&req);
1872
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001873 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001874 if (err < 0)
1875 mgmt_pending_remove(cmd);
1876
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001877failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001878 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001879 return err;
1880}
1881
Johan Hedberg406d7802013-03-15 17:07:09 -05001882static void write_fast_connectable(struct hci_request *req, bool enable)
1883{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001884 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001885 struct hci_cp_write_page_scan_activity acp;
1886 u8 type;
1887
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001888 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg547003b2013-10-21 16:51:53 +03001889 return;
1890
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001891 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1892 return;
1893
Johan Hedberg406d7802013-03-15 17:07:09 -05001894 if (enable) {
1895 type = PAGE_SCAN_TYPE_INTERLACED;
1896
1897 /* 160 msec page scan interval */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001898 acp.interval = cpu_to_le16(0x0100);
Johan Hedberg406d7802013-03-15 17:07:09 -05001899 } else {
1900 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1901
1902 /* default 1.28 sec page scan */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001903 acp.interval = cpu_to_le16(0x0800);
Johan Hedberg406d7802013-03-15 17:07:09 -05001904 }
1905
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001906 acp.window = cpu_to_le16(0x0012);
Johan Hedberg406d7802013-03-15 17:07:09 -05001907
Johan Hedbergbd98b992013-03-15 17:07:13 -05001908 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1909 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1910 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1911 sizeof(acp), &acp);
1912
1913 if (hdev->page_scan_type != type)
1914 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001915}
1916
Marcel Holtmann1904a852015-01-11 13:50:44 -08001917static void set_connectable_complete(struct hci_dev *hdev, u8 status,
1918 u16 opcode)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001919{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001920 struct mgmt_pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001921 struct mgmt_mode *cp;
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001922 bool conn_changed, discov_changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001923
1924 BT_DBG("status 0x%02x", status);
1925
1926 hci_dev_lock(hdev);
1927
1928 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1929 if (!cmd)
1930 goto unlock;
1931
Johan Hedberg37438c12013-10-14 16:20:05 +03001932 if (status) {
1933 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001934 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001935 goto remove_cmd;
1936 }
1937
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001938 cp = cmd->param;
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001939 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001940 conn_changed = !hci_dev_test_and_set_flag(hdev,
1941 HCI_CONNECTABLE);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001942 discov_changed = false;
1943 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001944 conn_changed = hci_dev_test_and_clear_flag(hdev,
1945 HCI_CONNECTABLE);
1946 discov_changed = hci_dev_test_and_clear_flag(hdev,
1947 HCI_DISCOVERABLE);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001948 }
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001949
Johan Hedberg2b76f452013-03-15 17:07:04 -05001950 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1951
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001952 if (conn_changed || discov_changed) {
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001953 new_settings(hdev, cmd->sk);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001954 hci_update_page_scan(hdev);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001955 if (discov_changed)
1956 mgmt_update_adv_data(hdev);
Johan Hedberg2b7be332014-07-07 14:40:22 +03001957 hci_update_background_scan(hdev);
1958 }
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001959
Johan Hedberg37438c12013-10-14 16:20:05 +03001960remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001961 mgmt_pending_remove(cmd);
1962
1963unlock:
1964 hci_dev_unlock(hdev);
1965}
1966
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001967static int set_connectable_update_settings(struct hci_dev *hdev,
1968 struct sock *sk, u8 val)
1969{
1970 bool changed = false;
1971 int err;
1972
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001973 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001974 changed = true;
1975
1976 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001977 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001978 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001979 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1980 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001981 }
1982
1983 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1984 if (err < 0)
1985 return err;
1986
Johan Hedberg562064e2014-07-08 16:35:34 +03001987 if (changed) {
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001988 hci_update_page_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001989 hci_update_background_scan(hdev);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001990 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001991 }
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001992
1993 return 0;
1994}
1995
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001996static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001997 u16 len)
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001998{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001999 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002000 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05002001 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03002002 u8 scan;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002003 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002004
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002005 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002006
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002007 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
2008 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02002009 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
2010 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03002011
Johan Hedberga7e80f22013-01-09 16:05:19 +02002012 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002013 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
2014 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002015
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002016 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002017
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002018 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03002019 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002020 goto failed;
2021 }
2022
2023 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002024 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002025 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
2026 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002027 goto failed;
2028 }
2029
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002030 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
2031 if (!cmd) {
2032 err = -ENOMEM;
2033 goto failed;
2034 }
2035
Johan Hedberg2b76f452013-03-15 17:07:04 -05002036 hci_req_init(&req, hdev);
2037
Johan Hedberg9a43e252013-10-20 19:00:07 +03002038 /* If BR/EDR is not enabled and we disable advertising as a
2039 * by-product of disabling connectable, we need to update the
2040 * advertising flags.
2041 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002042 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg9a43e252013-10-20 19:00:07 +03002043 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002044 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
2045 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg9a43e252013-10-20 19:00:07 +03002046 }
2047 update_adv_data(&req);
2048 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03002049 if (cp->val) {
2050 scan = SCAN_PAGE;
2051 } else {
Johan Hedberg3bd27242014-07-28 20:53:58 +03002052 /* If we don't have any whitelist entries just
2053 * disable all scanning. If there are entries
2054 * and we had both page and inquiry scanning
2055 * enabled then fall back to only page scanning.
2056 * Otherwise no changes are needed.
2057 */
2058 if (list_empty(&hdev->whitelist))
2059 scan = SCAN_DISABLED;
2060 else if (test_bit(HCI_ISCAN, &hdev->flags))
2061 scan = SCAN_PAGE;
2062 else
2063 goto no_scan_update;
Johan Hedberg9b742462013-10-14 16:20:03 +03002064
2065 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07002066 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03002067 cancel_delayed_work(&hdev->discov_off);
2068 }
2069
2070 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
2071 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05002072
Johan Hedberg3bd27242014-07-28 20:53:58 +03002073no_scan_update:
Johan Hedberge8b12022014-07-10 10:51:27 +03002074 /* Update the advertising parameters if necessary */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002075 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedberg1987fdc2013-10-14 21:15:24 +03002076 enable_advertising(&req);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03002077
Johan Hedberg2b76f452013-03-15 17:07:04 -05002078 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03002079 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002080 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03002081 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03002082 err = set_connectable_update_settings(hdev, sk,
2083 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03002084 goto failed;
2085 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002086
2087failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002088 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002089 return err;
2090}
2091
Johan Hedbergb2939472014-07-30 09:22:23 +03002092static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002093 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002094{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002095 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07002096 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002097 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002098
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002099 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002100
Johan Hedberga7e80f22013-01-09 16:05:19 +02002101 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002102 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
2103 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002104
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002105 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002106
2107 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07002108 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002109 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002110 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002111
Johan Hedbergb2939472014-07-30 09:22:23 +03002112 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002113 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07002114 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002115
Marcel Holtmann55594352013-10-06 16:11:57 -07002116 if (changed)
2117 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002118
Marcel Holtmann55594352013-10-06 16:11:57 -07002119unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002120 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002121 return err;
2122}
Johan Hedberg72a734e2010-12-30 00:38:22 +02002123
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002124static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
2125 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002126{
2127 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002128 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03002129 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002130 int err;
2131
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002132 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002133
Johan Hedberge6fe7982013-10-02 15:45:22 +03002134 status = mgmt_bredr_support(hdev);
2135 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002136 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2137 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03002138
Johan Hedberga7e80f22013-01-09 16:05:19 +02002139 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002140 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2141 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002142
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002143 hci_dev_lock(hdev);
2144
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002145 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02002146 bool changed = false;
2147
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002148 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07002149 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02002150 changed = true;
2151 }
2152
2153 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
2154 if (err < 0)
2155 goto failed;
2156
2157 if (changed)
2158 err = new_settings(hdev, sk);
2159
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002160 goto failed;
2161 }
2162
2163 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002164 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2165 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002166 goto failed;
2167 }
2168
2169 val = !!cp->val;
2170
2171 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
2172 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
2173 goto failed;
2174 }
2175
2176 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
2177 if (!cmd) {
2178 err = -ENOMEM;
2179 goto failed;
2180 }
2181
2182 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
2183 if (err < 0) {
2184 mgmt_pending_remove(cmd);
2185 goto failed;
2186 }
2187
2188failed:
2189 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002190 return err;
2191}
2192
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002193static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002194{
2195 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002196 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07002197 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002198 int err;
2199
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002200 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002201
Marcel Holtmanncdba5282013-10-02 21:31:52 -07002202 status = mgmt_bredr_support(hdev);
2203 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002204 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07002205
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002206 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002207 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2208 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002209
Johan Hedberga7e80f22013-01-09 16:05:19 +02002210 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002211 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2212 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002213
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002214 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02002215
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002216 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002217 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02002218
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002219 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07002220 changed = !hci_dev_test_and_set_flag(hdev,
2221 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002222 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002223 changed = hci_dev_test_and_clear_flag(hdev,
2224 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002225 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002226 changed = hci_dev_test_and_clear_flag(hdev,
2227 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002228 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002229 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02002230 }
2231
2232 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
2233 if (err < 0)
2234 goto failed;
2235
2236 if (changed)
2237 err = new_settings(hdev, sk);
2238
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002239 goto failed;
2240 }
2241
Johan Hedberg94d52da2015-02-19 17:38:06 +02002242 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002243 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2244 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002245 goto failed;
2246 }
2247
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002248 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002249 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
2250 goto failed;
2251 }
2252
2253 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
2254 if (!cmd) {
2255 err = -ENOMEM;
2256 goto failed;
2257 }
2258
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002259 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03002260 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
2261 sizeof(cp->val), &cp->val);
2262
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07002263 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002264 if (err < 0) {
2265 mgmt_pending_remove(cmd);
2266 goto failed;
2267 }
2268
2269failed:
2270 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002271 return err;
2272}
2273
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002274static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002275{
2276 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07002277 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03002278 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07002279 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002280
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002281 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002282
Johan Hedberge6fe7982013-10-02 15:45:22 +03002283 status = mgmt_bredr_support(hdev);
2284 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002285 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002286
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002287 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002288 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2289 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002290
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002291 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02002292 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2293 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002294
Johan Hedberga7e80f22013-01-09 16:05:19 +02002295 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002296 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2297 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002298
Marcel Holtmannee392692013-10-01 22:59:23 -07002299 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002300
Johan Hedberga2cb01d2015-02-19 17:38:07 +02002301 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002302 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2303 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02002304 goto unlock;
2305 }
2306
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002307 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07002308 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002309 } else {
2310 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002311 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2312 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002313 goto unlock;
2314 }
2315
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002316 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002317 }
Marcel Holtmannee392692013-10-01 22:59:23 -07002318
2319 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
2320 if (err < 0)
2321 goto unlock;
2322
2323 if (changed)
2324 err = new_settings(hdev, sk);
2325
2326unlock:
2327 hci_dev_unlock(hdev);
2328 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002329}
2330
Marcel Holtmann1904a852015-01-11 13:50:44 -08002331static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002332{
2333 struct cmd_lookup match = { NULL, hdev };
2334
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302335 hci_dev_lock(hdev);
2336
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002337 if (status) {
2338 u8 mgmt_err = mgmt_status(status);
2339
2340 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
2341 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302342 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002343 }
2344
2345 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
2346
2347 new_settings(hdev, match.sk);
2348
2349 if (match.sk)
2350 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002351
2352 /* Make sure the controller has a good default for
2353 * advertising data. Restrict the update to when LE
2354 * has actually been enabled. During power on, the
2355 * update in powered_update_hci will take care of it.
2356 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002357 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002358 struct hci_request req;
2359
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002360 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07002361 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07002362 update_scan_rsp_data(&req);
Johan Hedberg2cf22212014-12-19 22:26:00 +02002363 __hci_update_background_scan(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002364 hci_req_run(&req, NULL);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002365 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302366
2367unlock:
2368 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002369}
2370
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002371static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002372{
2373 struct mgmt_mode *cp = data;
2374 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002375 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002376 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002377 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002378 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002379
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002380 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002381
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002382 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002383 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2384 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002385
Johan Hedberga7e80f22013-01-09 16:05:19 +02002386 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002387 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2388 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002389
Johan Hedbergc73eee92013-04-19 18:35:21 +03002390 /* LE-only devices do not allow toggling LE on/off */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002391 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02002392 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2393 MGMT_STATUS_REJECTED);
Johan Hedbergc73eee92013-04-19 18:35:21 +03002394
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002395 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002396
2397 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02002398 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002399
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002400 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02002401 bool changed = false;
2402
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002403 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07002404 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002405 changed = true;
2406 }
2407
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002408 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002409 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03002410 changed = true;
2411 }
2412
Johan Hedberg06199cf2012-02-22 16:37:11 +02002413 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
2414 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08002415 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002416
2417 if (changed)
2418 err = new_settings(hdev, sk);
2419
Johan Hedberg1de028c2012-02-29 19:55:35 -08002420 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002421 }
2422
Johan Hedberg4375f102013-09-25 13:26:10 +03002423 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
2424 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002425 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2426 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002427 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002428 }
2429
2430 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
2431 if (!cmd) {
2432 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08002433 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002434 }
2435
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002436 hci_req_init(&req, hdev);
2437
Johan Hedberg06199cf2012-02-22 16:37:11 +02002438 memset(&hci_cp, 0, sizeof(hci_cp));
2439
2440 if (val) {
2441 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02002442 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002443 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002444 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002445 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002446 }
2447
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002448 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
2449 &hci_cp);
2450
2451 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05302452 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002453 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002454
Johan Hedberg1de028c2012-02-29 19:55:35 -08002455unlock:
2456 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002457 return err;
2458}
2459
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002460/* This is a helper function to test for pending mgmt commands that can
2461 * cause CoD or EIR HCI commands. We can only allow one such pending
2462 * mgmt command at a time since otherwise we cannot easily track what
2463 * the current values are, will be, and based on that calculate if a new
2464 * HCI command needs to be sent and if yes with what value.
2465 */
2466static bool pending_eir_or_class(struct hci_dev *hdev)
2467{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002468 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002469
2470 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2471 switch (cmd->opcode) {
2472 case MGMT_OP_ADD_UUID:
2473 case MGMT_OP_REMOVE_UUID:
2474 case MGMT_OP_SET_DEV_CLASS:
2475 case MGMT_OP_SET_POWERED:
2476 return true;
2477 }
2478 }
2479
2480 return false;
2481}
2482
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002483static const u8 bluetooth_base_uuid[] = {
2484 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2485 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2486};
2487
2488static u8 get_uuid_size(const u8 *uuid)
2489{
2490 u32 val;
2491
2492 if (memcmp(uuid, bluetooth_base_uuid, 12))
2493 return 128;
2494
2495 val = get_unaligned_le32(&uuid[12]);
2496 if (val > 0xffff)
2497 return 32;
2498
2499 return 16;
2500}
2501
Johan Hedberg92da6092013-03-15 17:06:55 -05002502static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2503{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002504 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002505
2506 hci_dev_lock(hdev);
2507
2508 cmd = mgmt_pending_find(mgmt_op, hdev);
2509 if (!cmd)
2510 goto unlock;
2511
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002512 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2513 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002514
2515 mgmt_pending_remove(cmd);
2516
2517unlock:
2518 hci_dev_unlock(hdev);
2519}
2520
Marcel Holtmann1904a852015-01-11 13:50:44 -08002521static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002522{
2523 BT_DBG("status 0x%02x", status);
2524
2525 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2526}
2527
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002528static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002529{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002530 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002531 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002532 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002533 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002534 int err;
2535
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002536 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002537
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002538 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002539
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002540 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002541 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2542 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002543 goto failed;
2544 }
2545
Andre Guedes92c4c202012-06-07 19:05:44 -03002546 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002547 if (!uuid) {
2548 err = -ENOMEM;
2549 goto failed;
2550 }
2551
2552 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002553 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002554 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002555
Johan Hedbergde66aa62013-01-27 00:31:27 +02002556 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002557
Johan Hedberg890ea892013-03-15 17:06:52 -05002558 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002559
Johan Hedberg890ea892013-03-15 17:06:52 -05002560 update_class(&req);
2561 update_eir(&req);
2562
Johan Hedberg92da6092013-03-15 17:06:55 -05002563 err = hci_req_run(&req, add_uuid_complete);
2564 if (err < 0) {
2565 if (err != -ENODATA)
2566 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002567
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002568 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2569 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002570 goto failed;
2571 }
2572
2573 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002574 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002575 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002576 goto failed;
2577 }
2578
2579 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002580
2581failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002582 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002583 return err;
2584}
2585
Johan Hedberg24b78d02012-02-23 23:24:30 +02002586static bool enable_service_cache(struct hci_dev *hdev)
2587{
2588 if (!hdev_is_powered(hdev))
2589 return false;
2590
Marcel Holtmann238be782015-03-13 02:11:06 -07002591 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002592 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2593 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002594 return true;
2595 }
2596
2597 return false;
2598}
2599
Marcel Holtmann1904a852015-01-11 13:50:44 -08002600static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002601{
2602 BT_DBG("status 0x%02x", status);
2603
2604 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2605}
2606
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002607static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002608 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002609{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002610 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002611 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002612 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002613 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 -05002614 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002615 int err, found;
2616
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002617 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002618
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002619 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002620
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002621 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002622 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2623 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002624 goto unlock;
2625 }
2626
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002627 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002628 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002629
Johan Hedberg24b78d02012-02-23 23:24:30 +02002630 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002631 err = mgmt_cmd_complete(sk, hdev->id,
2632 MGMT_OP_REMOVE_UUID,
2633 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002634 goto unlock;
2635 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002636
Johan Hedberg9246a862012-02-23 21:33:16 +02002637 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002638 }
2639
2640 found = 0;
2641
Johan Hedberg056341c2013-01-27 00:31:30 +02002642 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002643 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2644 continue;
2645
2646 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002647 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002648 found++;
2649 }
2650
2651 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002652 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2653 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002654 goto unlock;
2655 }
2656
Johan Hedberg9246a862012-02-23 21:33:16 +02002657update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002658 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002659
Johan Hedberg890ea892013-03-15 17:06:52 -05002660 update_class(&req);
2661 update_eir(&req);
2662
Johan Hedberg92da6092013-03-15 17:06:55 -05002663 err = hci_req_run(&req, remove_uuid_complete);
2664 if (err < 0) {
2665 if (err != -ENODATA)
2666 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002667
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002668 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2669 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002670 goto unlock;
2671 }
2672
2673 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002674 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002675 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002676 goto unlock;
2677 }
2678
2679 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002680
2681unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002682 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002683 return err;
2684}
2685
Marcel Holtmann1904a852015-01-11 13:50:44 -08002686static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002687{
2688 BT_DBG("status 0x%02x", status);
2689
2690 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2691}
2692
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002693static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002694 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002695{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002696 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002697 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002698 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002699 int err;
2700
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002701 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002702
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002703 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002704 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2705 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002706
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002707 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002708
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002709 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002710 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2711 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002712 goto unlock;
2713 }
2714
2715 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002716 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2717 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002718 goto unlock;
2719 }
2720
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002721 hdev->major_class = cp->major;
2722 hdev->minor_class = cp->minor;
2723
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002724 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002725 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2726 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002727 goto unlock;
2728 }
2729
Johan Hedberg890ea892013-03-15 17:06:52 -05002730 hci_req_init(&req, hdev);
2731
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002732 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002733 hci_dev_unlock(hdev);
2734 cancel_delayed_work_sync(&hdev->service_cache);
2735 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002736 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002737 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002738
Johan Hedberg890ea892013-03-15 17:06:52 -05002739 update_class(&req);
2740
Johan Hedberg92da6092013-03-15 17:06:55 -05002741 err = hci_req_run(&req, set_class_complete);
2742 if (err < 0) {
2743 if (err != -ENODATA)
2744 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002745
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002746 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2747 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002748 goto unlock;
2749 }
2750
2751 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002752 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002753 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002754 goto unlock;
2755 }
2756
2757 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002758
Johan Hedbergb5235a62012-02-21 14:32:24 +02002759unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002760 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002761 return err;
2762}
2763
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002764static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002765 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002766{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002767 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002768 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2769 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002770 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002771 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002772 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002773
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002774 BT_DBG("request for %s", hdev->name);
2775
2776 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002777 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2778 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002779
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002780 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002781 if (key_count > max_key_count) {
2782 BT_ERR("load_link_keys: too big key_count value %u",
2783 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002784 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2785 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002786 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002787
Johan Hedberg86742e12011-11-07 23:13:38 +02002788 expected_len = sizeof(*cp) + key_count *
2789 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002790 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002791 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002792 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002793 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2794 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002795 }
2796
Johan Hedberg4ae14302013-01-20 14:27:13 +02002797 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002798 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2799 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002800
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002801 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002802 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002803
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002804 for (i = 0; i < key_count; i++) {
2805 struct mgmt_link_key_info *key = &cp->keys[i];
2806
Marcel Holtmann8e991132014-01-10 02:07:25 -08002807 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002808 return mgmt_cmd_status(sk, hdev->id,
2809 MGMT_OP_LOAD_LINK_KEYS,
2810 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002811 }
2812
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002813 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002814
2815 hci_link_keys_clear(hdev);
2816
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002817 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002818 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002819 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002820 changed = hci_dev_test_and_clear_flag(hdev,
2821 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002822
2823 if (changed)
2824 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002825
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002826 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002827 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002828
Johan Hedberg58e92932014-06-24 14:00:26 +03002829 /* Always ignore debug keys and require a new pairing if
2830 * the user wants to use them.
2831 */
2832 if (key->type == HCI_LK_DEBUG_COMBINATION)
2833 continue;
2834
Johan Hedberg7652ff62014-06-24 13:15:49 +03002835 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2836 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002837 }
2838
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002839 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002840
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002841 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002842
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002843 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002844}
2845
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002846static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002847 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002848{
2849 struct mgmt_ev_device_unpaired ev;
2850
2851 bacpy(&ev.addr.bdaddr, bdaddr);
2852 ev.addr.type = addr_type;
2853
2854 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002855 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002856}
2857
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002858static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002859 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002860{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002861 struct mgmt_cp_unpair_device *cp = data;
2862 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002863 struct hci_cp_disconnect dc;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002864 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002865 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002866 int err;
2867
Johan Hedberga8a1d192011-11-10 15:54:38 +02002868 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002869 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2870 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002871
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002872 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002873 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2874 MGMT_STATUS_INVALID_PARAMS,
2875 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002876
Johan Hedberg118da702013-01-20 14:27:20 +02002877 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002878 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2879 MGMT_STATUS_INVALID_PARAMS,
2880 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002881
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002882 hci_dev_lock(hdev);
2883
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002884 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002885 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2886 MGMT_STATUS_NOT_POWERED, &rp,
2887 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002888 goto unlock;
2889 }
2890
Johan Hedberge0b2b272014-02-18 17:14:31 +02002891 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002892 /* If disconnection is requested, then look up the
2893 * connection. If the remote device is connected, it
2894 * will be later used to terminate the link.
2895 *
2896 * Setting it to NULL explicitly will cause no
2897 * termination of the link.
2898 */
2899 if (cp->disconnect)
2900 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2901 &cp->addr.bdaddr);
2902 else
2903 conn = NULL;
2904
Johan Hedberg124f6e32012-02-09 13:50:12 +02002905 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedberge0b2b272014-02-18 17:14:31 +02002906 } else {
2907 u8 addr_type;
2908
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002909 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
2910 &cp->addr.bdaddr);
2911 if (conn) {
2912 /* Defer clearing up the connection parameters
2913 * until closing to give a chance of keeping
2914 * them if a repairing happens.
2915 */
2916 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2917
2918 /* If disconnection is not requested, then
2919 * clear the connection variable so that the
2920 * link is not terminated.
2921 */
2922 if (!cp->disconnect)
2923 conn = NULL;
2924 }
2925
Johan Hedberge0b2b272014-02-18 17:14:31 +02002926 if (cp->addr.type == BDADDR_LE_PUBLIC)
2927 addr_type = ADDR_LE_DEV_PUBLIC;
2928 else
2929 addr_type = ADDR_LE_DEV_RANDOM;
2930
Johan Hedberga7ec7332014-02-18 17:14:35 +02002931 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2932
Johan Hedberge0b2b272014-02-18 17:14:31 +02002933 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
2934 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002935
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002936 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002937 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2938 MGMT_STATUS_NOT_PAIRED, &rp,
2939 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002940 goto unlock;
2941 }
2942
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002943 /* If the connection variable is set, then termination of the
2944 * link is requested.
2945 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002946 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002947 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2948 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002949 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002950 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002951 }
2952
Johan Hedberg124f6e32012-02-09 13:50:12 +02002953 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002954 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002955 if (!cmd) {
2956 err = -ENOMEM;
2957 goto unlock;
2958 }
2959
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002960 cmd->cmd_complete = addr_cmd_complete;
2961
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002962 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002963 dc.reason = 0x13; /* Remote User Terminated Connection */
2964 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2965 if (err < 0)
2966 mgmt_pending_remove(cmd);
2967
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002968unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002969 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002970 return err;
2971}
2972
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002973static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002974 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002975{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002976 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002977 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002978 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002979 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002980 int err;
2981
2982 BT_DBG("");
2983
Johan Hedberg06a63b12013-01-20 14:27:21 +02002984 memset(&rp, 0, sizeof(rp));
2985 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2986 rp.addr.type = cp->addr.type;
2987
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002988 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002989 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2990 MGMT_STATUS_INVALID_PARAMS,
2991 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002992
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002993 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002994
2995 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002996 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2997 MGMT_STATUS_NOT_POWERED, &rp,
2998 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002999 goto failed;
3000 }
3001
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003002 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003003 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
3004 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003005 goto failed;
3006 }
3007
Andre Guedes591f47f2012-04-24 21:02:49 -03003008 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003009 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
3010 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02003011 else
3012 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03003013
Vishal Agarwalf9607272012-06-13 05:32:43 +05303014 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003015 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
3016 MGMT_STATUS_NOT_CONNECTED, &rp,
3017 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003018 goto failed;
3019 }
3020
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003021 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03003022 if (!cmd) {
3023 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003024 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03003025 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02003026
Johan Hedbergf5818c22014-12-05 13:36:02 +02003027 cmd->cmd_complete = generic_cmd_complete;
3028
Johan Hedberge3f2f922014-08-18 20:33:33 +03003029 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003030 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03003031 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003032
3033failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003034 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003035 return err;
3036}
3037
Andre Guedes57c14772012-04-24 21:02:50 -03003038static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02003039{
3040 switch (link_type) {
3041 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02003042 switch (addr_type) {
3043 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03003044 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03003045
Johan Hedberg48264f02011-11-09 13:58:58 +02003046 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03003047 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03003048 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02003049 }
Andre Guedes0ed09142012-04-03 08:46:54 -03003050
Johan Hedberg4c659c32011-11-07 23:13:39 +02003051 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03003052 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03003053 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02003054 }
3055}
3056
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003057static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
3058 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02003059{
Johan Hedberg2784eb42011-01-21 13:56:35 +02003060 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02003061 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02003062 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003063 int err;
3064 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02003065
3066 BT_DBG("");
3067
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003068 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003069
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003070 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003071 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
3072 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003073 goto unlock;
3074 }
3075
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003076 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02003077 list_for_each_entry(c, &hdev->conn_hash.list, list) {
3078 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003079 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02003080 }
3081
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003082 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03003083 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02003084 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02003085 err = -ENOMEM;
3086 goto unlock;
3087 }
3088
Johan Hedberg2784eb42011-01-21 13:56:35 +02003089 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02003090 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02003091 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
3092 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02003093 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03003094 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03003095 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02003096 continue;
3097 i++;
3098 }
3099
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003100 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003101
Johan Hedberg4c659c32011-11-07 23:13:39 +02003102 /* Recalculate length in case of filtered SCO connections, etc */
3103 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02003104
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003105 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
3106 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003107
Johan Hedberga38528f2011-01-22 06:46:43 +02003108 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003109
3110unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003111 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003112 return err;
3113}
3114
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003115static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003116 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003117{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003118 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003119 int err;
3120
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003121 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003122 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003123 if (!cmd)
3124 return -ENOMEM;
3125
Johan Hedbergd8457692012-02-17 14:24:57 +02003126 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003127 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003128 if (err < 0)
3129 mgmt_pending_remove(cmd);
3130
3131 return err;
3132}
3133
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003134static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003135 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003136{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003137 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003138 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003139 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003140 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003141 int err;
3142
3143 BT_DBG("");
3144
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003145 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003146
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003147 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003148 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3149 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003150 goto failed;
3151 }
3152
Johan Hedbergd8457692012-02-17 14:24:57 +02003153 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003154 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003155 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3156 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003157 goto failed;
3158 }
3159
3160 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02003161 struct mgmt_cp_pin_code_neg_reply ncp;
3162
3163 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003164
3165 BT_ERR("PIN code is not 16 bytes long");
3166
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003167 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003168 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02003169 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3170 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003171
3172 goto failed;
3173 }
3174
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03003175 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03003176 if (!cmd) {
3177 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003178 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03003179 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02003180
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003181 cmd->cmd_complete = addr_cmd_complete;
3182
Johan Hedbergd8457692012-02-17 14:24:57 +02003183 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003184 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02003185 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003186
3187 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
3188 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03003189 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003190
3191failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003192 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003193 return err;
3194}
3195
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003196static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
3197 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003198{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003199 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003200
3201 BT_DBG("");
3202
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003203 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003204 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
3205 MGMT_STATUS_INVALID_PARAMS, NULL, 0);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003206
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003207 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003208
3209 hdev->io_capability = cp->io_capability;
3210
3211 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003212 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003213
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003214 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003215
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003216 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
3217 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003218}
3219
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003220static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003221{
3222 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003223 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003224
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003225 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03003226 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
3227 continue;
3228
Johan Hedberge9a416b2011-02-19 12:05:56 -03003229 if (cmd->user_data != conn)
3230 continue;
3231
3232 return cmd;
3233 }
3234
3235 return NULL;
3236}
3237
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003238static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003239{
3240 struct mgmt_rp_pair_device rp;
3241 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02003242 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003243
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02003244 bacpy(&rp.addr.bdaddr, &conn->dst);
3245 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003246
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003247 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
3248 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003249
3250 /* So we don't get further callbacks for this connection */
3251 conn->connect_cfm_cb = NULL;
3252 conn->security_cfm_cb = NULL;
3253 conn->disconn_cfm_cb = NULL;
3254
David Herrmann76a68ba2013-04-06 20:28:37 +02003255 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00003256
3257 /* The device is paired so there is no need to remove
3258 * its connection parameters anymore.
3259 */
3260 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02003261
3262 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02003263
3264 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003265}
3266
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003267void mgmt_smp_complete(struct hci_conn *conn, bool complete)
3268{
3269 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003270 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003271
3272 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003273 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02003274 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02003275 mgmt_pending_remove(cmd);
3276 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003277}
3278
Johan Hedberge9a416b2011-02-19 12:05:56 -03003279static void pairing_complete_cb(struct hci_conn *conn, u8 status)
3280{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003281 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003282
3283 BT_DBG("status %u", status);
3284
Johan Hedberg56e5cb82011-11-08 20:40:16 +02003285 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003286 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02003287 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02003288 return;
3289 }
3290
3291 cmd->cmd_complete(cmd, mgmt_status(status));
3292 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003293}
3294
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003295static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303296{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003297 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303298
3299 BT_DBG("status %u", status);
3300
3301 if (!status)
3302 return;
3303
3304 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003305 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303306 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02003307 return;
3308 }
3309
3310 cmd->cmd_complete(cmd, mgmt_status(status));
3311 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303312}
3313
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003314static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003315 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003316{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003317 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02003318 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003319 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003320 u8 sec_level, auth_type;
3321 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003322 int err;
3323
3324 BT_DBG("");
3325
Szymon Jancf950a30e2013-01-18 12:48:07 +01003326 memset(&rp, 0, sizeof(rp));
3327 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3328 rp.addr.type = cp->addr.type;
3329
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003330 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003331 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3332 MGMT_STATUS_INVALID_PARAMS,
3333 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003334
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003335 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003336 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3337 MGMT_STATUS_INVALID_PARAMS,
3338 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003339
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003340 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003341
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003342 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003343 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3344 MGMT_STATUS_NOT_POWERED, &rp,
3345 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003346 goto unlock;
3347 }
3348
Johan Hedberg55e76b32015-03-10 22:34:40 +02003349 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
3350 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3351 MGMT_STATUS_ALREADY_PAIRED, &rp,
3352 sizeof(rp));
3353 goto unlock;
3354 }
3355
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03003356 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02003357 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003358
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003359 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03003360 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
3361 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003362 } else {
3363 u8 addr_type;
3364
3365 /* Convert from L2CAP channel address type to HCI address type
3366 */
3367 if (cp->addr.type == BDADDR_LE_PUBLIC)
3368 addr_type = ADDR_LE_DEV_PUBLIC;
3369 else
3370 addr_type = ADDR_LE_DEV_RANDOM;
3371
Marcel Holtmann7c264b12014-06-30 12:34:40 +02003372 /* When pairing a new device, it is expected to remember
3373 * this device for future connections. Adding the connection
3374 * parameter information ahead of time allows tracking
3375 * of the slave preferred values and will speed up any
3376 * further connection establishment.
3377 *
3378 * If connection parameters already exist, then they
3379 * will be kept and this function does nothing.
3380 */
3381 hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
3382
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003383 conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type,
Johan Hedberge804d252014-07-16 11:42:28 +03003384 sec_level, HCI_LE_CONN_TIMEOUT,
3385 HCI_ROLE_MASTER);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003386 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003387
Ville Tervo30e76272011-02-22 16:10:53 -03003388 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003389 int status;
3390
3391 if (PTR_ERR(conn) == -EBUSY)
3392 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01003393 else if (PTR_ERR(conn) == -EOPNOTSUPP)
3394 status = MGMT_STATUS_NOT_SUPPORTED;
3395 else if (PTR_ERR(conn) == -ECONNREFUSED)
3396 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003397 else
3398 status = MGMT_STATUS_CONNECT_FAILED;
3399
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003400 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3401 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003402 goto unlock;
3403 }
3404
3405 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02003406 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003407 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3408 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003409 goto unlock;
3410 }
3411
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003412 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003413 if (!cmd) {
3414 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02003415 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003416 goto unlock;
3417 }
3418
Johan Hedberg04ab2742014-12-05 13:36:04 +02003419 cmd->cmd_complete = pairing_complete;
3420
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003421 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003422 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003423 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003424 conn->security_cfm_cb = pairing_complete_cb;
3425 conn->disconn_cfm_cb = pairing_complete_cb;
3426 } else {
3427 conn->connect_cfm_cb = le_pairing_complete_cb;
3428 conn->security_cfm_cb = le_pairing_complete_cb;
3429 conn->disconn_cfm_cb = le_pairing_complete_cb;
3430 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003431
Johan Hedberge9a416b2011-02-19 12:05:56 -03003432 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003433 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003434
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003435 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003436 hci_conn_security(conn, sec_level, auth_type, true)) {
3437 cmd->cmd_complete(cmd, 0);
3438 mgmt_pending_remove(cmd);
3439 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003440
3441 err = 0;
3442
3443unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003444 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003445 return err;
3446}
3447
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003448static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3449 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003450{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003451 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003452 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003453 struct hci_conn *conn;
3454 int err;
3455
3456 BT_DBG("");
3457
Johan Hedberg28424702012-02-02 04:02:29 +02003458 hci_dev_lock(hdev);
3459
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003460 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003461 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3462 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003463 goto unlock;
3464 }
3465
Johan Hedberg28424702012-02-02 04:02:29 +02003466 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
3467 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003468 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3469 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003470 goto unlock;
3471 }
3472
3473 conn = cmd->user_data;
3474
3475 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003476 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3477 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003478 goto unlock;
3479 }
3480
Johan Hedberga511b352014-12-11 21:45:45 +02003481 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3482 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003483
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003484 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3485 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003486unlock:
3487 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003488 return err;
3489}
3490
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003491static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003492 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003493 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003494{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003495 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003496 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003497 int err;
3498
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003499 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003500
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003501 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003502 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3503 MGMT_STATUS_NOT_POWERED, addr,
3504 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003505 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003506 }
3507
Johan Hedberg1707c602013-03-15 17:07:15 -05003508 if (addr->type == BDADDR_BREDR)
3509 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003510 else
Johan Hedberg1707c602013-03-15 17:07:15 -05003511 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08003512
Johan Hedberg272d90d2012-02-09 15:26:12 +02003513 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003514 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3515 MGMT_STATUS_NOT_CONNECTED, addr,
3516 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003517 goto done;
3518 }
3519
Johan Hedberg1707c602013-03-15 17:07:15 -05003520 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003521 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003522 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003523 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3524 MGMT_STATUS_SUCCESS, addr,
3525 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003526 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003527 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3528 MGMT_STATUS_FAILED, addr,
3529 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003530
Brian Gix47c15e22011-11-16 13:53:14 -08003531 goto done;
3532 }
3533
Johan Hedberg1707c602013-03-15 17:07:15 -05003534 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003535 if (!cmd) {
3536 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003537 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003538 }
3539
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003540 cmd->cmd_complete = addr_cmd_complete;
3541
Brian Gix0df4c182011-11-16 13:53:13 -08003542 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003543 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3544 struct hci_cp_user_passkey_reply cp;
3545
Johan Hedberg1707c602013-03-15 17:07:15 -05003546 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003547 cp.passkey = passkey;
3548 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3549 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003550 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3551 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003552
Johan Hedberga664b5b2011-02-19 12:06:02 -03003553 if (err < 0)
3554 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003555
Brian Gix0df4c182011-11-16 13:53:13 -08003556done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003557 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003558 return err;
3559}
3560
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303561static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3562 void *data, u16 len)
3563{
3564 struct mgmt_cp_pin_code_neg_reply *cp = data;
3565
3566 BT_DBG("");
3567
Johan Hedberg1707c602013-03-15 17:07:15 -05003568 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303569 MGMT_OP_PIN_CODE_NEG_REPLY,
3570 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3571}
3572
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003573static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3574 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003575{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003576 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003577
3578 BT_DBG("");
3579
3580 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003581 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3582 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003583
Johan Hedberg1707c602013-03-15 17:07:15 -05003584 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003585 MGMT_OP_USER_CONFIRM_REPLY,
3586 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003587}
3588
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003589static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003590 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003591{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003592 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003593
3594 BT_DBG("");
3595
Johan Hedberg1707c602013-03-15 17:07:15 -05003596 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003597 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3598 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003599}
3600
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003601static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3602 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003603{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003604 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003605
3606 BT_DBG("");
3607
Johan Hedberg1707c602013-03-15 17:07:15 -05003608 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003609 MGMT_OP_USER_PASSKEY_REPLY,
3610 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003611}
3612
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003613static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003614 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003615{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003616 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003617
3618 BT_DBG("");
3619
Johan Hedberg1707c602013-03-15 17:07:15 -05003620 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003621 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3622 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003623}
3624
Johan Hedberg13928972013-03-15 17:07:00 -05003625static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003626{
Johan Hedberg13928972013-03-15 17:07:00 -05003627 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003628 struct hci_cp_write_local_name cp;
3629
Johan Hedberg13928972013-03-15 17:07:00 -05003630 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003631
Johan Hedberg890ea892013-03-15 17:06:52 -05003632 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003633}
3634
Marcel Holtmann1904a852015-01-11 13:50:44 -08003635static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003636{
3637 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003638 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003639
3640 BT_DBG("status 0x%02x", status);
3641
3642 hci_dev_lock(hdev);
3643
3644 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
3645 if (!cmd)
3646 goto unlock;
3647
3648 cp = cmd->param;
3649
3650 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003651 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3652 mgmt_status(status));
Johan Hedberg13928972013-03-15 17:07:00 -05003653 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003654 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3655 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003656
3657 mgmt_pending_remove(cmd);
3658
3659unlock:
3660 hci_dev_unlock(hdev);
3661}
3662
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003663static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003664 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003665{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003666 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003667 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003668 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003669 int err;
3670
3671 BT_DBG("");
3672
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003673 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003674
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003675 /* If the old values are the same as the new ones just return a
3676 * direct command complete event.
3677 */
3678 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3679 !memcmp(hdev->short_name, cp->short_name,
3680 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003681 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3682 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003683 goto failed;
3684 }
3685
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003686 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003687
Johan Hedbergb5235a62012-02-21 14:32:24 +02003688 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003689 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003690
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003691 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3692 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003693 if (err < 0)
3694 goto failed;
3695
Marcel Holtmannf6b77122015-03-14 19:28:05 -07003696 err = mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev,
3697 data, len, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003698
Johan Hedbergb5235a62012-02-21 14:32:24 +02003699 goto failed;
3700 }
3701
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003702 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003703 if (!cmd) {
3704 err = -ENOMEM;
3705 goto failed;
3706 }
3707
Johan Hedberg13928972013-03-15 17:07:00 -05003708 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3709
Johan Hedberg890ea892013-03-15 17:06:52 -05003710 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003711
3712 if (lmp_bredr_capable(hdev)) {
3713 update_name(&req);
3714 update_eir(&req);
3715 }
3716
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003717 /* The name is stored in the scan response data and so
3718 * no need to udpate the advertising data here.
3719 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003720 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003721 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003722
Johan Hedberg13928972013-03-15 17:07:00 -05003723 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003724 if (err < 0)
3725 mgmt_pending_remove(cmd);
3726
3727failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003728 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003729 return err;
3730}
3731
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003732static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003733 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003734{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003735 struct mgmt_pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01003736 int err;
3737
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003738 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003739
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003740 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003741
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003742 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003743 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3744 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003745 goto unlock;
3746 }
3747
Andre Guedes9a1a1992012-07-24 15:03:48 -03003748 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003749 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3750 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003751 goto unlock;
3752 }
3753
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003754 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003755 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3756 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003757 goto unlock;
3758 }
3759
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003760 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003761 if (!cmd) {
3762 err = -ENOMEM;
3763 goto unlock;
3764 }
3765
Johan Hedberg710f11c2014-05-26 11:21:22 +03003766 if (bredr_sc_enabled(hdev))
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003767 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
3768 0, NULL);
3769 else
3770 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3771
Szymon Jancc35938b2011-03-22 13:12:21 +01003772 if (err < 0)
3773 mgmt_pending_remove(cmd);
3774
3775unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003776 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003777 return err;
3778}
3779
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003780static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003781 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003782{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003783 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003784 int err;
3785
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003786 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003787
Johan Hedberg5d57e792015-01-23 10:10:38 +02003788 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003789 return mgmt_cmd_complete(sk, hdev->id,
3790 MGMT_OP_ADD_REMOTE_OOB_DATA,
3791 MGMT_STATUS_INVALID_PARAMS,
3792 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003793
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003794 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003795
Marcel Holtmannec109112014-01-10 02:07:30 -08003796 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3797 struct mgmt_cp_add_remote_oob_data *cp = data;
3798 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003799
Johan Hedbergc19a4952014-11-17 20:52:19 +02003800 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003801 err = mgmt_cmd_complete(sk, hdev->id,
3802 MGMT_OP_ADD_REMOTE_OOB_DATA,
3803 MGMT_STATUS_INVALID_PARAMS,
3804 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003805 goto unlock;
3806 }
3807
Marcel Holtmannec109112014-01-10 02:07:30 -08003808 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003809 cp->addr.type, cp->hash,
3810 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003811 if (err < 0)
3812 status = MGMT_STATUS_FAILED;
3813 else
3814 status = MGMT_STATUS_SUCCESS;
3815
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003816 err = mgmt_cmd_complete(sk, hdev->id,
3817 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3818 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003819 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3820 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003821 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003822 u8 status;
3823
Johan Hedberg86df9202014-10-26 20:52:27 +01003824 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003825 /* Enforce zero-valued 192-bit parameters as
3826 * long as legacy SMP OOB isn't implemented.
3827 */
3828 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3829 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003830 err = mgmt_cmd_complete(sk, hdev->id,
3831 MGMT_OP_ADD_REMOTE_OOB_DATA,
3832 MGMT_STATUS_INVALID_PARAMS,
3833 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003834 goto unlock;
3835 }
3836
Johan Hedberg86df9202014-10-26 20:52:27 +01003837 rand192 = NULL;
3838 hash192 = NULL;
3839 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003840 /* In case one of the P-192 values is set to zero,
3841 * then just disable OOB data for P-192.
3842 */
3843 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3844 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3845 rand192 = NULL;
3846 hash192 = NULL;
3847 } else {
3848 rand192 = cp->rand192;
3849 hash192 = cp->hash192;
3850 }
3851 }
3852
3853 /* In case one of the P-256 values is set to zero, then just
3854 * disable OOB data for P-256.
3855 */
3856 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3857 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3858 rand256 = NULL;
3859 hash256 = NULL;
3860 } else {
3861 rand256 = cp->rand256;
3862 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003863 }
3864
Johan Hedberg81328d52014-10-26 20:33:47 +01003865 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003866 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003867 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003868 if (err < 0)
3869 status = MGMT_STATUS_FAILED;
3870 else
3871 status = MGMT_STATUS_SUCCESS;
3872
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003873 err = mgmt_cmd_complete(sk, hdev->id,
3874 MGMT_OP_ADD_REMOTE_OOB_DATA,
3875 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003876 } else {
3877 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003878 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3879 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003880 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003881
Johan Hedbergc19a4952014-11-17 20:52:19 +02003882unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003883 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003884 return err;
3885}
3886
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003887static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003888 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003889{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003890 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003891 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003892 int err;
3893
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003894 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003895
Johan Hedbergc19a4952014-11-17 20:52:19 +02003896 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003897 return mgmt_cmd_complete(sk, hdev->id,
3898 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3899 MGMT_STATUS_INVALID_PARAMS,
3900 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003901
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003902 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003903
Johan Hedbergeedbd582014-11-15 09:34:23 +02003904 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3905 hci_remote_oob_data_clear(hdev);
3906 status = MGMT_STATUS_SUCCESS;
3907 goto done;
3908 }
3909
Johan Hedberg6928a922014-10-26 20:46:09 +01003910 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003911 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003912 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003913 else
Szymon Janca6785be2012-12-13 15:11:21 +01003914 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003915
Johan Hedbergeedbd582014-11-15 09:34:23 +02003916done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003917 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3918 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003919
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003920 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003921 return err;
3922}
3923
Marcel Holtmann80190442014-12-04 11:36:36 +01003924static bool trigger_discovery(struct hci_request *req, u8 *status)
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003925{
Marcel Holtmann80190442014-12-04 11:36:36 +01003926 struct hci_dev *hdev = req->hdev;
3927 struct hci_cp_le_set_scan_param param_cp;
3928 struct hci_cp_le_set_scan_enable enable_cp;
3929 struct hci_cp_inquiry inq_cp;
3930 /* General inquiry access code (GIAC) */
3931 u8 lap[3] = { 0x33, 0x8b, 0x9e };
3932 u8 own_addr_type;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003933 int err;
3934
Marcel Holtmann80190442014-12-04 11:36:36 +01003935 switch (hdev->discovery.type) {
3936 case DISCOV_TYPE_BREDR:
3937 *status = mgmt_bredr_support(hdev);
3938 if (*status)
3939 return false;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003940
Marcel Holtmann80190442014-12-04 11:36:36 +01003941 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3942 *status = MGMT_STATUS_BUSY;
3943 return false;
3944 }
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003945
Marcel Holtmann80190442014-12-04 11:36:36 +01003946 hci_inquiry_cache_flush(hdev);
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003947
Marcel Holtmann80190442014-12-04 11:36:36 +01003948 memset(&inq_cp, 0, sizeof(inq_cp));
3949 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
3950 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
3951 hci_req_add(req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
3952 break;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003953
Marcel Holtmann80190442014-12-04 11:36:36 +01003954 case DISCOV_TYPE_LE:
3955 case DISCOV_TYPE_INTERLEAVED:
3956 *status = mgmt_le_support(hdev);
3957 if (*status)
3958 return false;
3959
3960 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003961 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmann80190442014-12-04 11:36:36 +01003962 *status = MGMT_STATUS_NOT_SUPPORTED;
3963 return false;
3964 }
3965
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003966 if (hci_dev_test_flag(hdev, HCI_LE_ADV)) {
Marcel Holtmann80190442014-12-04 11:36:36 +01003967 /* Don't let discovery abort an outgoing
3968 * connection attempt that's using directed
3969 * advertising.
3970 */
3971 if (hci_conn_hash_lookup_state(hdev, LE_LINK,
3972 BT_CONNECT)) {
3973 *status = MGMT_STATUS_REJECTED;
3974 return false;
3975 }
3976
3977 disable_advertising(req);
3978 }
3979
3980 /* If controller is scanning, it means the background scanning
3981 * is running. Thus, we should temporarily stop it in order to
3982 * set the discovery scanning parameters.
3983 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07003984 if (hci_dev_test_flag(hdev, HCI_LE_SCAN))
Marcel Holtmann80190442014-12-04 11:36:36 +01003985 hci_req_add_le_scan_disable(req);
3986
3987 memset(&param_cp, 0, sizeof(param_cp));
3988
3989 /* All active scans will be done with either a resolvable
3990 * private address (when privacy feature has been enabled)
Marcel Holtmann9437d2e2014-12-07 20:13:17 +01003991 * or non-resolvable private address.
Marcel Holtmann80190442014-12-04 11:36:36 +01003992 */
3993 err = hci_update_random_address(req, true, &own_addr_type);
3994 if (err < 0) {
3995 *status = MGMT_STATUS_FAILED;
3996 return false;
3997 }
3998
3999 param_cp.type = LE_SCAN_ACTIVE;
4000 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
4001 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
4002 param_cp.own_address_type = own_addr_type;
4003 hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
4004 &param_cp);
4005
4006 memset(&enable_cp, 0, sizeof(enable_cp));
4007 enable_cp.enable = LE_SCAN_ENABLE;
4008 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
4009 hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
4010 &enable_cp);
4011 break;
4012
4013 default:
4014 *status = MGMT_STATUS_INVALID_PARAMS;
4015 return false;
4016 }
4017
4018 return true;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03004019}
4020
Marcel Holtmann1904a852015-01-11 13:50:44 -08004021static void start_discovery_complete(struct hci_dev *hdev, u8 status,
4022 u16 opcode)
Andre Guedes7c307722013-04-30 15:29:28 -03004023{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004024 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004025 unsigned long timeout;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004026
Andre Guedes7c307722013-04-30 15:29:28 -03004027 BT_DBG("status %d", status);
4028
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004029 hci_dev_lock(hdev);
4030
4031 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004032 if (!cmd)
4033 cmd = mgmt_pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
4034
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004035 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004036 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004037 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03004038 }
4039
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004040 if (status) {
4041 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
4042 goto unlock;
4043 }
4044
Andre Guedes7c307722013-04-30 15:29:28 -03004045 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
Andre Guedes7c307722013-04-30 15:29:28 -03004046
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004047 /* If the scan involves LE scan, pick proper timeout to schedule
4048 * hdev->le_scan_disable that will stop it.
4049 */
Andre Guedes7c307722013-04-30 15:29:28 -03004050 switch (hdev->discovery.type) {
4051 case DISCOV_TYPE_LE:
Lukasz Rymanowski3d5a76f2014-03-27 20:55:21 +01004052 timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03004053 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004054 case DISCOV_TYPE_INTERLEAVED:
Lukasz Rymanowskib9a7a612014-03-27 20:55:20 +01004055 timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
Andre Guedes7c307722013-04-30 15:29:28 -03004056 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004057 case DISCOV_TYPE_BREDR:
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004058 timeout = 0;
Andre Guedes7c307722013-04-30 15:29:28 -03004059 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004060 default:
4061 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004062 timeout = 0;
4063 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004064 }
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004065
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004066 if (timeout) {
4067 /* When service discovery is used and the controller has
4068 * a strict duplicate filter, it is important to remember
4069 * the start and duration of the scan. This is required
4070 * for restarting scanning during the discovery phase.
4071 */
4072 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER,
4073 &hdev->quirks) &&
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004074 hdev->discovery.result_filtering) {
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004075 hdev->discovery.scan_start = jiffies;
4076 hdev->discovery.scan_duration = timeout;
4077 }
4078
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004079 queue_delayed_work(hdev->workqueue,
4080 &hdev->le_scan_disable, timeout);
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004081 }
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004082
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004083unlock:
4084 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03004085}
4086
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004087static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004088 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004089{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004090 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004091 struct mgmt_pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03004092 struct hci_request req;
Marcel Holtmann80190442014-12-04 11:36:36 +01004093 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04004094 int err;
4095
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004096 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004097
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004098 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004099
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004100 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004101 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4102 MGMT_STATUS_NOT_POWERED,
4103 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02004104 goto failed;
4105 }
4106
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004107 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004108 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004109 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4110 MGMT_STATUS_BUSY, &cp->type,
4111 sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03004112 goto failed;
4113 }
4114
Johan Hedberg2922a942014-12-05 13:36:06 +02004115 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004116 if (!cmd) {
4117 err = -ENOMEM;
4118 goto failed;
4119 }
4120
Johan Hedberg2922a942014-12-05 13:36:06 +02004121 cmd->cmd_complete = generic_cmd_complete;
4122
Marcel Holtmann22078802014-12-05 11:45:22 +01004123 /* Clear the discovery filter first to free any previously
4124 * allocated memory for the UUID list.
4125 */
4126 hci_discovery_filter_clear(hdev);
4127
Andre Guedes4aab14e2012-02-17 20:39:36 -03004128 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01004129 hdev->discovery.report_invalid_rssi = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03004130
Andre Guedes7c307722013-04-30 15:29:28 -03004131 hci_req_init(&req, hdev);
4132
Marcel Holtmann80190442014-12-04 11:36:36 +01004133 if (!trigger_discovery(&req, &status)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004134 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4135 status, &cp->type, sizeof(cp->type));
Johan Hedberg04106752013-01-10 14:54:09 +02004136 mgmt_pending_remove(cmd);
4137 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004138 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004139
Andre Guedes7c307722013-04-30 15:29:28 -03004140 err = hci_req_run(&req, start_discovery_complete);
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004141 if (err < 0) {
Johan Hedberg14a53662011-04-27 10:29:56 -04004142 mgmt_pending_remove(cmd);
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004143 goto failed;
4144 }
4145
4146 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04004147
4148failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004149 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004150 return err;
4151}
4152
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004153static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4154 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004155{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004156 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4157 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004158}
4159
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004160static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4161 void *data, u16 len)
4162{
4163 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004164 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004165 struct hci_request req;
4166 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4167 u16 uuid_count, expected_len;
4168 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004169 int err;
4170
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004171 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004172
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004173 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004174
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004175 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004176 err = mgmt_cmd_complete(sk, hdev->id,
4177 MGMT_OP_START_SERVICE_DISCOVERY,
4178 MGMT_STATUS_NOT_POWERED,
4179 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004180 goto failed;
4181 }
4182
4183 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004184 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004185 err = mgmt_cmd_complete(sk, hdev->id,
4186 MGMT_OP_START_SERVICE_DISCOVERY,
4187 MGMT_STATUS_BUSY, &cp->type,
4188 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004189 goto failed;
4190 }
4191
4192 uuid_count = __le16_to_cpu(cp->uuid_count);
4193 if (uuid_count > max_uuid_count) {
4194 BT_ERR("service_discovery: too big uuid_count value %u",
4195 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004196 err = mgmt_cmd_complete(sk, hdev->id,
4197 MGMT_OP_START_SERVICE_DISCOVERY,
4198 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4199 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004200 goto failed;
4201 }
4202
4203 expected_len = sizeof(*cp) + uuid_count * 16;
4204 if (expected_len != len) {
4205 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
4206 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004207 err = mgmt_cmd_complete(sk, hdev->id,
4208 MGMT_OP_START_SERVICE_DISCOVERY,
4209 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4210 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004211 goto failed;
4212 }
4213
4214 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02004215 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004216 if (!cmd) {
4217 err = -ENOMEM;
4218 goto failed;
4219 }
4220
Johan Hedberg2922a942014-12-05 13:36:06 +02004221 cmd->cmd_complete = service_discovery_cmd_complete;
4222
Marcel Holtmann22078802014-12-05 11:45:22 +01004223 /* Clear the discovery filter first to free any previously
4224 * allocated memory for the UUID list.
4225 */
4226 hci_discovery_filter_clear(hdev);
4227
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004228 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004229 hdev->discovery.type = cp->type;
4230 hdev->discovery.rssi = cp->rssi;
4231 hdev->discovery.uuid_count = uuid_count;
4232
4233 if (uuid_count > 0) {
4234 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4235 GFP_KERNEL);
4236 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004237 err = mgmt_cmd_complete(sk, hdev->id,
4238 MGMT_OP_START_SERVICE_DISCOVERY,
4239 MGMT_STATUS_FAILED,
4240 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004241 mgmt_pending_remove(cmd);
4242 goto failed;
4243 }
4244 }
4245
4246 hci_req_init(&req, hdev);
4247
4248 if (!trigger_discovery(&req, &status)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004249 err = mgmt_cmd_complete(sk, hdev->id,
4250 MGMT_OP_START_SERVICE_DISCOVERY,
4251 status, &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004252 mgmt_pending_remove(cmd);
4253 goto failed;
4254 }
4255
4256 err = hci_req_run(&req, start_discovery_complete);
4257 if (err < 0) {
4258 mgmt_pending_remove(cmd);
4259 goto failed;
4260 }
4261
4262 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
4263
4264failed:
4265 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004266 return err;
4267}
4268
Marcel Holtmann1904a852015-01-11 13:50:44 -08004269static void stop_discovery_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004270{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004271 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004272
Andre Guedes0e05bba2013-04-30 15:29:33 -03004273 BT_DBG("status %d", status);
4274
4275 hci_dev_lock(hdev);
4276
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004277 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
4278 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004279 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004280 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004281 }
4282
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004283 if (!status)
4284 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004285
Andre Guedes0e05bba2013-04-30 15:29:33 -03004286 hci_dev_unlock(hdev);
4287}
4288
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004289static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004290 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004291{
Johan Hedbergd9306502012-02-20 23:25:18 +02004292 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004293 struct mgmt_pending_cmd *cmd;
Andre Guedes0e05bba2013-04-30 15:29:33 -03004294 struct hci_request req;
Johan Hedberg14a53662011-04-27 10:29:56 -04004295 int err;
4296
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004297 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004298
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004299 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004300
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004301 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004302 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4303 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4304 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004305 goto unlock;
4306 }
4307
4308 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004309 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4310 MGMT_STATUS_INVALID_PARAMS,
4311 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004312 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004313 }
4314
Johan Hedberg2922a942014-12-05 13:36:06 +02004315 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004316 if (!cmd) {
4317 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004318 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004319 }
4320
Johan Hedberg2922a942014-12-05 13:36:06 +02004321 cmd->cmd_complete = generic_cmd_complete;
4322
Andre Guedes0e05bba2013-04-30 15:29:33 -03004323 hci_req_init(&req, hdev);
4324
Johan Hedberg21a60d32014-06-10 14:05:58 +03004325 hci_stop_discovery(&req);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004326
Johan Hedberg21a60d32014-06-10 14:05:58 +03004327 err = hci_req_run(&req, stop_discovery_complete);
4328 if (!err) {
4329 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004330 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004331 }
4332
Johan Hedberg21a60d32014-06-10 14:05:58 +03004333 mgmt_pending_remove(cmd);
4334
4335 /* If no HCI commands were sent we're done */
4336 if (err == -ENODATA) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004337 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
4338 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg21a60d32014-06-10 14:05:58 +03004339 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
4340 }
Johan Hedberg14a53662011-04-27 10:29:56 -04004341
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004342unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004343 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004344 return err;
4345}
4346
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004347static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004348 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004349{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004350 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004351 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004352 int err;
4353
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004354 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004355
Johan Hedberg561aafb2012-01-04 13:31:59 +02004356 hci_dev_lock(hdev);
4357
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004358 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004359 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4360 MGMT_STATUS_FAILED, &cp->addr,
4361 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004362 goto failed;
4363 }
4364
Johan Hedberga198e7b2012-02-17 14:27:06 +02004365 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004366 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004367 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4368 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4369 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004370 goto failed;
4371 }
4372
4373 if (cp->name_known) {
4374 e->name_state = NAME_KNOWN;
4375 list_del(&e->list);
4376 } else {
4377 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02004378 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004379 }
4380
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004381 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4382 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004383
4384failed:
4385 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004386 return err;
4387}
4388
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004389static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004390 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004391{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004392 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004393 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004394 int err;
4395
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004396 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004397
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004398 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004399 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4400 MGMT_STATUS_INVALID_PARAMS,
4401 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004402
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004403 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004404
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004405 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4406 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004407 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004408 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004409 goto done;
4410 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004411
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004412 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4413 sk);
4414 status = MGMT_STATUS_SUCCESS;
4415
4416done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004417 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4418 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004419
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004420 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004421
4422 return err;
4423}
4424
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004425static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004426 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004427{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004428 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004429 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004430 int err;
4431
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004432 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004433
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004434 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004435 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4436 MGMT_STATUS_INVALID_PARAMS,
4437 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004438
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004439 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004440
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004441 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4442 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004443 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004444 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004445 goto done;
4446 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004447
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004448 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4449 sk);
4450 status = MGMT_STATUS_SUCCESS;
4451
4452done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004453 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4454 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004455
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004456 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004457
4458 return err;
4459}
4460
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004461static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4462 u16 len)
4463{
4464 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004465 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004466 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004467 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004468
4469 BT_DBG("%s", hdev->name);
4470
Szymon Jancc72d4b82012-03-16 16:02:57 +01004471 source = __le16_to_cpu(cp->source);
4472
4473 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004474 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4475 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004476
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004477 hci_dev_lock(hdev);
4478
Szymon Jancc72d4b82012-03-16 16:02:57 +01004479 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004480 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4481 hdev->devid_product = __le16_to_cpu(cp->product);
4482 hdev->devid_version = __le16_to_cpu(cp->version);
4483
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004484 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4485 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004486
Johan Hedberg890ea892013-03-15 17:06:52 -05004487 hci_req_init(&req, hdev);
4488 update_eir(&req);
4489 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004490
4491 hci_dev_unlock(hdev);
4492
4493 return err;
4494}
4495
Marcel Holtmann1904a852015-01-11 13:50:44 -08004496static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4497 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004498{
4499 struct cmd_lookup match = { NULL, hdev };
4500
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304501 hci_dev_lock(hdev);
4502
Johan Hedberg4375f102013-09-25 13:26:10 +03004503 if (status) {
4504 u8 mgmt_err = mgmt_status(status);
4505
4506 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4507 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304508 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004509 }
4510
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004511 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004512 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004513 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004514 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004515
Johan Hedberg4375f102013-09-25 13:26:10 +03004516 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4517 &match);
4518
4519 new_settings(hdev, match.sk);
4520
4521 if (match.sk)
4522 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304523
4524unlock:
4525 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004526}
4527
Marcel Holtmann21b51872013-10-10 09:47:53 -07004528static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4529 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004530{
4531 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004532 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004533 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004534 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004535 int err;
4536
4537 BT_DBG("request for %s", hdev->name);
4538
Johan Hedberge6fe7982013-10-02 15:45:22 +03004539 status = mgmt_le_support(hdev);
4540 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004541 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4542 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004543
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004544 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004545 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4546 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004547
4548 hci_dev_lock(hdev);
4549
4550 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004551
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004552 /* The following conditions are ones which mean that we should
4553 * not do any HCI communication but directly send a mgmt
4554 * response to user space (after toggling the flag if
4555 * necessary).
4556 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004557 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004558 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4559 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004560 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004561 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004562 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004563 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004564
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004565 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004566 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004567 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004568 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004569 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004570 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004571 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004572 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004573 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004574 }
4575
4576 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4577 if (err < 0)
4578 goto unlock;
4579
4580 if (changed)
4581 err = new_settings(hdev, sk);
4582
4583 goto unlock;
4584 }
4585
4586 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4587 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004588 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4589 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004590 goto unlock;
4591 }
4592
4593 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4594 if (!cmd) {
4595 err = -ENOMEM;
4596 goto unlock;
4597 }
4598
4599 hci_req_init(&req, hdev);
4600
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004601 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004602 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004603 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004604 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004605
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004606 if (val)
4607 enable_advertising(&req);
4608 else
4609 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03004610
4611 err = hci_req_run(&req, set_advertising_complete);
4612 if (err < 0)
4613 mgmt_pending_remove(cmd);
4614
4615unlock:
4616 hci_dev_unlock(hdev);
4617 return err;
4618}
4619
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004620static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4621 void *data, u16 len)
4622{
4623 struct mgmt_cp_set_static_address *cp = data;
4624 int err;
4625
4626 BT_DBG("%s", hdev->name);
4627
Marcel Holtmann62af4442013-10-02 22:10:32 -07004628 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004629 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4630 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004631
4632 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004633 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4634 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004635
4636 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4637 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004638 return mgmt_cmd_status(sk, hdev->id,
4639 MGMT_OP_SET_STATIC_ADDRESS,
4640 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004641
4642 /* Two most significant bits shall be set */
4643 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004644 return mgmt_cmd_status(sk, hdev->id,
4645 MGMT_OP_SET_STATIC_ADDRESS,
4646 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004647 }
4648
4649 hci_dev_lock(hdev);
4650
4651 bacpy(&hdev->static_addr, &cp->bdaddr);
4652
Marcel Holtmann93690c22015-03-06 10:11:21 -08004653 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4654 if (err < 0)
4655 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004656
Marcel Holtmann93690c22015-03-06 10:11:21 -08004657 err = new_settings(hdev, sk);
4658
4659unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004660 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004661 return err;
4662}
4663
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004664static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4665 void *data, u16 len)
4666{
4667 struct mgmt_cp_set_scan_params *cp = data;
4668 __u16 interval, window;
4669 int err;
4670
4671 BT_DBG("%s", hdev->name);
4672
4673 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004674 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4675 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004676
4677 interval = __le16_to_cpu(cp->interval);
4678
4679 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004680 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4681 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004682
4683 window = __le16_to_cpu(cp->window);
4684
4685 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004686 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4687 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004688
Marcel Holtmann899e1072013-10-14 09:55:32 -07004689 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004690 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4691 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004692
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004693 hci_dev_lock(hdev);
4694
4695 hdev->le_scan_interval = interval;
4696 hdev->le_scan_window = window;
4697
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004698 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4699 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004700
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004701 /* If background scan is running, restart it so new parameters are
4702 * loaded.
4703 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004704 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004705 hdev->discovery.state == DISCOVERY_STOPPED) {
4706 struct hci_request req;
4707
4708 hci_req_init(&req, hdev);
4709
4710 hci_req_add_le_scan_disable(&req);
4711 hci_req_add_le_passive_scan(&req);
4712
4713 hci_req_run(&req, NULL);
4714 }
4715
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004716 hci_dev_unlock(hdev);
4717
4718 return err;
4719}
4720
Marcel Holtmann1904a852015-01-11 13:50:44 -08004721static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4722 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004723{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004724 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004725
4726 BT_DBG("status 0x%02x", status);
4727
4728 hci_dev_lock(hdev);
4729
4730 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4731 if (!cmd)
4732 goto unlock;
4733
4734 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004735 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4736 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004737 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004738 struct mgmt_mode *cp = cmd->param;
4739
4740 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004741 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004742 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004743 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004744
Johan Hedberg33e38b32013-03-15 17:07:05 -05004745 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4746 new_settings(hdev, cmd->sk);
4747 }
4748
4749 mgmt_pending_remove(cmd);
4750
4751unlock:
4752 hci_dev_unlock(hdev);
4753}
4754
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004755static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004756 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004757{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004758 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004759 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004760 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004761 int err;
4762
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004763 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004764
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004765 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004766 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004767 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4768 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004769
Johan Hedberga7e80f22013-01-09 16:05:19 +02004770 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004771 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4772 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004773
Antti Julkuf6422ec2011-06-22 13:11:56 +03004774 hci_dev_lock(hdev);
4775
Johan Hedberg05cbf292013-03-15 17:07:07 -05004776 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004777 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4778 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004779 goto unlock;
4780 }
4781
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004782 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004783 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4784 hdev);
4785 goto unlock;
4786 }
4787
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004788 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004789 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004790 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4791 hdev);
4792 new_settings(hdev, sk);
4793 goto unlock;
4794 }
4795
Johan Hedberg33e38b32013-03-15 17:07:05 -05004796 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4797 data, len);
4798 if (!cmd) {
4799 err = -ENOMEM;
4800 goto unlock;
4801 }
4802
4803 hci_req_init(&req, hdev);
4804
Johan Hedberg406d7802013-03-15 17:07:09 -05004805 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004806
4807 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004808 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004809 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4810 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004811 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004812 }
4813
Johan Hedberg33e38b32013-03-15 17:07:05 -05004814unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004815 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004816
Antti Julkuf6422ec2011-06-22 13:11:56 +03004817 return err;
4818}
4819
Marcel Holtmann1904a852015-01-11 13:50:44 -08004820static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004821{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004822 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004823
4824 BT_DBG("status 0x%02x", status);
4825
4826 hci_dev_lock(hdev);
4827
4828 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
4829 if (!cmd)
4830 goto unlock;
4831
4832 if (status) {
4833 u8 mgmt_err = mgmt_status(status);
4834
4835 /* We need to restore the flag if related HCI commands
4836 * failed.
4837 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004838 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004839
Johan Hedberga69e8372015-03-06 21:08:53 +02004840 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004841 } else {
4842 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4843 new_settings(hdev, cmd->sk);
4844 }
4845
4846 mgmt_pending_remove(cmd);
4847
4848unlock:
4849 hci_dev_unlock(hdev);
4850}
4851
4852static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4853{
4854 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004855 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004856 struct hci_request req;
4857 int err;
4858
4859 BT_DBG("request for %s", hdev->name);
4860
4861 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004862 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4863 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004864
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004865 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004866 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4867 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004868
4869 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004870 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4871 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004872
4873 hci_dev_lock(hdev);
4874
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004875 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004876 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4877 goto unlock;
4878 }
4879
4880 if (!hdev_is_powered(hdev)) {
4881 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004882 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4883 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4884 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4885 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4886 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004887 }
4888
Marcel Holtmannce05d602015-03-13 02:11:03 -07004889 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004890
4891 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4892 if (err < 0)
4893 goto unlock;
4894
4895 err = new_settings(hdev, sk);
4896 goto unlock;
4897 }
4898
4899 /* Reject disabling when powered on */
4900 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004901 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4902 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004903 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004904 } else {
4905 /* When configuring a dual-mode controller to operate
4906 * with LE only and using a static address, then switching
4907 * BR/EDR back on is not allowed.
4908 *
4909 * Dual-mode controllers shall operate with the public
4910 * address as its identity address for BR/EDR and LE. So
4911 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004912 *
4913 * The same restrictions applies when secure connections
4914 * has been enabled. For BR/EDR this is a controller feature
4915 * while for LE it is a host stack feature. This means that
4916 * switching BR/EDR back on when secure connections has been
4917 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004918 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004919 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004920 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004921 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004922 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4923 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004924 goto unlock;
4925 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004926 }
4927
4928 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004929 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4930 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004931 goto unlock;
4932 }
4933
4934 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4935 if (!cmd) {
4936 err = -ENOMEM;
4937 goto unlock;
4938 }
4939
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004940 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03004941 * generates the correct flags.
4942 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004943 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004944
4945 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004946
Johan Hedberg432df052014-08-01 11:13:31 +03004947 write_fast_connectable(&req, false);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02004948 __hci_update_page_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004949
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004950 /* Since only the advertising data flags will change, there
4951 * is no need to update the scan response data.
4952 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004953 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004954
Johan Hedberg0663ca22013-10-02 13:43:14 +03004955 err = hci_req_run(&req, set_bredr_complete);
4956 if (err < 0)
4957 mgmt_pending_remove(cmd);
4958
4959unlock:
4960 hci_dev_unlock(hdev);
4961 return err;
4962}
4963
Johan Hedberga1443f52015-01-23 15:42:46 +02004964static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
4965{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004966 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02004967 struct mgmt_mode *cp;
4968
4969 BT_DBG("%s status %u", hdev->name, status);
4970
4971 hci_dev_lock(hdev);
4972
4973 cmd = mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
4974 if (!cmd)
4975 goto unlock;
4976
4977 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004978 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
4979 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02004980 goto remove;
4981 }
4982
4983 cp = cmd->param;
4984
4985 switch (cp->val) {
4986 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004987 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
4988 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004989 break;
4990 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004991 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004992 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004993 break;
4994 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004995 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
4996 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02004997 break;
4998 }
4999
5000 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
5001 new_settings(hdev, cmd->sk);
5002
5003remove:
5004 mgmt_pending_remove(cmd);
5005unlock:
5006 hci_dev_unlock(hdev);
5007}
5008
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005009static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
5010 void *data, u16 len)
5011{
5012 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005013 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005014 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03005015 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005016 int err;
5017
5018 BT_DBG("request for %s", hdev->name);
5019
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005020 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005021 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005022 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5023 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005024
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005025 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02005026 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005027 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005028 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5029 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08005030
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005031 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005032 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005033 MGMT_STATUS_INVALID_PARAMS);
5034
5035 hci_dev_lock(hdev);
5036
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005037 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005038 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005039 bool changed;
5040
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005041 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005042 changed = !hci_dev_test_and_set_flag(hdev,
5043 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005044 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005045 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005046 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005047 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005048 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005049 changed = hci_dev_test_and_clear_flag(hdev,
5050 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005051 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005052 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005053
5054 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5055 if (err < 0)
5056 goto failed;
5057
5058 if (changed)
5059 err = new_settings(hdev, sk);
5060
5061 goto failed;
5062 }
5063
5064 if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005065 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5066 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005067 goto failed;
5068 }
5069
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005070 val = !!cp->val;
5071
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005072 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5073 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005074 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5075 goto failed;
5076 }
5077
5078 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
5079 if (!cmd) {
5080 err = -ENOMEM;
5081 goto failed;
5082 }
5083
Johan Hedberga1443f52015-01-23 15:42:46 +02005084 hci_req_init(&req, hdev);
5085 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
5086 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005087 if (err < 0) {
5088 mgmt_pending_remove(cmd);
5089 goto failed;
5090 }
5091
5092failed:
5093 hci_dev_unlock(hdev);
5094 return err;
5095}
5096
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005097static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
5098 void *data, u16 len)
5099{
5100 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03005101 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005102 int err;
5103
5104 BT_DBG("request for %s", hdev->name);
5105
Johan Hedbergb97109792014-06-24 14:00:28 +03005106 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005107 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
5108 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005109
5110 hci_dev_lock(hdev);
5111
5112 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07005113 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005114 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005115 changed = hci_dev_test_and_clear_flag(hdev,
5116 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005117
Johan Hedbergb97109792014-06-24 14:00:28 +03005118 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07005119 use_changed = !hci_dev_test_and_set_flag(hdev,
5120 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005121 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005122 use_changed = hci_dev_test_and_clear_flag(hdev,
5123 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005124
5125 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005126 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03005127 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
5128 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
5129 sizeof(mode), &mode);
5130 }
5131
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005132 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
5133 if (err < 0)
5134 goto unlock;
5135
5136 if (changed)
5137 err = new_settings(hdev, sk);
5138
5139unlock:
5140 hci_dev_unlock(hdev);
5141 return err;
5142}
5143
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005144static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5145 u16 len)
5146{
5147 struct mgmt_cp_set_privacy *cp = cp_data;
5148 bool changed;
5149 int err;
5150
5151 BT_DBG("request for %s", hdev->name);
5152
5153 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005154 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5155 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005156
5157 if (cp->privacy != 0x00 && cp->privacy != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005158 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5159 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005160
5161 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005162 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5163 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005164
5165 hci_dev_lock(hdev);
5166
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005167 /* If user space supports this command it is also expected to
5168 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
5169 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005170 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005171
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005172 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005173 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005174 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005175 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005176 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005177 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005178 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005179 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005180 }
5181
5182 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
5183 if (err < 0)
5184 goto unlock;
5185
5186 if (changed)
5187 err = new_settings(hdev, sk);
5188
5189unlock:
5190 hci_dev_unlock(hdev);
5191 return err;
5192}
5193
Johan Hedberg41edf162014-02-18 10:19:35 +02005194static bool irk_is_valid(struct mgmt_irk_info *irk)
5195{
5196 switch (irk->addr.type) {
5197 case BDADDR_LE_PUBLIC:
5198 return true;
5199
5200 case BDADDR_LE_RANDOM:
5201 /* Two most significant bits shall be set */
5202 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5203 return false;
5204 return true;
5205 }
5206
5207 return false;
5208}
5209
5210static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5211 u16 len)
5212{
5213 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005214 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5215 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005216 u16 irk_count, expected_len;
5217 int i, err;
5218
5219 BT_DBG("request for %s", hdev->name);
5220
5221 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005222 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5223 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005224
5225 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005226 if (irk_count > max_irk_count) {
5227 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005228 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5229 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005230 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005231
5232 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
5233 if (expected_len != len) {
5234 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02005235 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005236 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5237 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005238 }
5239
5240 BT_DBG("%s irk_count %u", hdev->name, irk_count);
5241
5242 for (i = 0; i < irk_count; i++) {
5243 struct mgmt_irk_info *key = &cp->irks[i];
5244
5245 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005246 return mgmt_cmd_status(sk, hdev->id,
5247 MGMT_OP_LOAD_IRKS,
5248 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005249 }
5250
5251 hci_dev_lock(hdev);
5252
5253 hci_smp_irks_clear(hdev);
5254
5255 for (i = 0; i < irk_count; i++) {
5256 struct mgmt_irk_info *irk = &cp->irks[i];
5257 u8 addr_type;
5258
5259 if (irk->addr.type == BDADDR_LE_PUBLIC)
5260 addr_type = ADDR_LE_DEV_PUBLIC;
5261 else
5262 addr_type = ADDR_LE_DEV_RANDOM;
5263
5264 hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
5265 BDADDR_ANY);
5266 }
5267
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005268 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005269
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005270 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005271
5272 hci_dev_unlock(hdev);
5273
5274 return err;
5275}
5276
Johan Hedberg3f706b72013-01-20 14:27:16 +02005277static bool ltk_is_valid(struct mgmt_ltk_info *key)
5278{
5279 if (key->master != 0x00 && key->master != 0x01)
5280 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005281
5282 switch (key->addr.type) {
5283 case BDADDR_LE_PUBLIC:
5284 return true;
5285
5286 case BDADDR_LE_RANDOM:
5287 /* Two most significant bits shall be set */
5288 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5289 return false;
5290 return true;
5291 }
5292
5293 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005294}
5295
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005296static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005297 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005298{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005299 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005300 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5301 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005302 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005303 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005304
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005305 BT_DBG("request for %s", hdev->name);
5306
5307 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005308 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5309 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005310
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005311 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005312 if (key_count > max_key_count) {
5313 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005314 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5315 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005316 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005317
5318 expected_len = sizeof(*cp) + key_count *
5319 sizeof(struct mgmt_ltk_info);
5320 if (expected_len != len) {
5321 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02005322 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005323 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5324 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005325 }
5326
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005327 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005328
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005329 for (i = 0; i < key_count; i++) {
5330 struct mgmt_ltk_info *key = &cp->keys[i];
5331
Johan Hedberg3f706b72013-01-20 14:27:16 +02005332 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005333 return mgmt_cmd_status(sk, hdev->id,
5334 MGMT_OP_LOAD_LONG_TERM_KEYS,
5335 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005336 }
5337
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005338 hci_dev_lock(hdev);
5339
5340 hci_smp_ltks_clear(hdev);
5341
5342 for (i = 0; i < key_count; i++) {
5343 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedbergd7b25452014-05-23 13:19:53 +03005344 u8 type, addr_type, authenticated;
Marcel Holtmann79d95a12013-10-13 03:57:38 -07005345
5346 if (key->addr.type == BDADDR_LE_PUBLIC)
5347 addr_type = ADDR_LE_DEV_PUBLIC;
5348 else
5349 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005350
Johan Hedberg61b43352014-05-29 19:36:53 +03005351 switch (key->type) {
5352 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005353 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005354 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005355 break;
5356 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005357 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005358 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005359 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005360 case MGMT_LTK_P256_UNAUTH:
5361 authenticated = 0x00;
5362 type = SMP_LTK_P256;
5363 break;
5364 case MGMT_LTK_P256_AUTH:
5365 authenticated = 0x01;
5366 type = SMP_LTK_P256;
5367 break;
5368 case MGMT_LTK_P256_DEBUG:
5369 authenticated = 0x00;
5370 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03005371 default:
5372 continue;
5373 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005374
Johan Hedberg35d70272014-02-19 14:57:47 +02005375 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type,
Johan Hedbergd7b25452014-05-23 13:19:53 +03005376 authenticated, key->val, key->enc_size, key->ediv,
Johan Hedberg35d70272014-02-19 14:57:47 +02005377 key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005378 }
5379
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005380 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005381 NULL, 0);
5382
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005383 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005384
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005385 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005386}
5387
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005388static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005389{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005390 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005391 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005392 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005393
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005394 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005395
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005396 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005397 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005398 rp.tx_power = conn->tx_power;
5399 rp.max_tx_power = conn->max_tx_power;
5400 } else {
5401 rp.rssi = HCI_RSSI_INVALID;
5402 rp.tx_power = HCI_TX_POWER_INVALID;
5403 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005404 }
5405
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005406 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5407 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005408
5409 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005410 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005411
5412 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005413}
5414
Marcel Holtmann1904a852015-01-11 13:50:44 -08005415static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5416 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005417{
5418 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005419 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005420 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005421 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005422 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005423
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005424 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005425
5426 hci_dev_lock(hdev);
5427
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005428 /* Commands sent in request are either Read RSSI or Read Transmit Power
5429 * Level so we check which one was last sent to retrieve connection
5430 * handle. Both commands have handle as first parameter so it's safe to
5431 * cast data on the same command struct.
5432 *
5433 * First command sent is always Read RSSI and we fail only if it fails.
5434 * In other case we simply override error to indicate success as we
5435 * already remembered if TX power value is actually valid.
5436 */
5437 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5438 if (!cp) {
5439 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005440 status = MGMT_STATUS_SUCCESS;
5441 } else {
5442 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005443 }
5444
5445 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005446 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005447 goto unlock;
5448 }
5449
5450 handle = __le16_to_cpu(cp->handle);
5451 conn = hci_conn_hash_lookup_handle(hdev, handle);
5452 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005453 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005454 goto unlock;
5455 }
5456
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005457 cmd = mgmt_pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
5458 if (!cmd)
5459 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005460
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005461 cmd->cmd_complete(cmd, status);
5462 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005463
5464unlock:
5465 hci_dev_unlock(hdev);
5466}
5467
5468static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5469 u16 len)
5470{
5471 struct mgmt_cp_get_conn_info *cp = data;
5472 struct mgmt_rp_get_conn_info rp;
5473 struct hci_conn *conn;
5474 unsigned long conn_info_age;
5475 int err = 0;
5476
5477 BT_DBG("%s", hdev->name);
5478
5479 memset(&rp, 0, sizeof(rp));
5480 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5481 rp.addr.type = cp->addr.type;
5482
5483 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005484 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5485 MGMT_STATUS_INVALID_PARAMS,
5486 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005487
5488 hci_dev_lock(hdev);
5489
5490 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005491 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5492 MGMT_STATUS_NOT_POWERED, &rp,
5493 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005494 goto unlock;
5495 }
5496
5497 if (cp->addr.type == BDADDR_BREDR)
5498 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5499 &cp->addr.bdaddr);
5500 else
5501 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5502
5503 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005504 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5505 MGMT_STATUS_NOT_CONNECTED, &rp,
5506 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005507 goto unlock;
5508 }
5509
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005510 if (mgmt_pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005511 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5512 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005513 goto unlock;
5514 }
5515
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005516 /* To avoid client trying to guess when to poll again for information we
5517 * calculate conn info age as random value between min/max set in hdev.
5518 */
5519 conn_info_age = hdev->conn_info_min_age +
5520 prandom_u32_max(hdev->conn_info_max_age -
5521 hdev->conn_info_min_age);
5522
5523 /* Query controller to refresh cached values if they are too old or were
5524 * never read.
5525 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005526 if (time_after(jiffies, conn->conn_info_timestamp +
5527 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005528 !conn->conn_info_timestamp) {
5529 struct hci_request req;
5530 struct hci_cp_read_tx_power req_txp_cp;
5531 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005532 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005533
5534 hci_req_init(&req, hdev);
5535 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5536 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5537 &req_rssi_cp);
5538
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005539 /* For LE links TX power does not change thus we don't need to
5540 * query for it once value is known.
5541 */
5542 if (!bdaddr_type_is_le(cp->addr.type) ||
5543 conn->tx_power == HCI_TX_POWER_INVALID) {
5544 req_txp_cp.handle = cpu_to_le16(conn->handle);
5545 req_txp_cp.type = 0x00;
5546 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5547 sizeof(req_txp_cp), &req_txp_cp);
5548 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005549
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005550 /* Max TX power needs to be read only once per connection */
5551 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5552 req_txp_cp.handle = cpu_to_le16(conn->handle);
5553 req_txp_cp.type = 0x01;
5554 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5555 sizeof(req_txp_cp), &req_txp_cp);
5556 }
5557
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005558 err = hci_req_run(&req, conn_info_refresh_complete);
5559 if (err < 0)
5560 goto unlock;
5561
5562 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5563 data, len);
5564 if (!cmd) {
5565 err = -ENOMEM;
5566 goto unlock;
5567 }
5568
5569 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005570 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005571 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005572
5573 conn->conn_info_timestamp = jiffies;
5574 } else {
5575 /* Cache is valid, just reply with values cached in hci_conn */
5576 rp.rssi = conn->rssi;
5577 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005578 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005579
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005580 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5581 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005582 }
5583
5584unlock:
5585 hci_dev_unlock(hdev);
5586 return err;
5587}
5588
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005589static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005590{
5591 struct hci_conn *conn = cmd->user_data;
5592 struct mgmt_rp_get_clock_info rp;
5593 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005594 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005595
5596 memset(&rp, 0, sizeof(rp));
5597 memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
5598
5599 if (status)
5600 goto complete;
5601
5602 hdev = hci_dev_get(cmd->index);
5603 if (hdev) {
5604 rp.local_clock = cpu_to_le32(hdev->clock);
5605 hci_dev_put(hdev);
5606 }
5607
5608 if (conn) {
5609 rp.piconet_clock = cpu_to_le32(conn->clock);
5610 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5611 }
5612
5613complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005614 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5615 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005616
5617 if (conn) {
5618 hci_conn_drop(conn);
5619 hci_conn_put(conn);
5620 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005621
5622 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005623}
5624
Marcel Holtmann1904a852015-01-11 13:50:44 -08005625static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005626{
Johan Hedberg95868422014-06-28 17:54:07 +03005627 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005628 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005629 struct hci_conn *conn;
5630
5631 BT_DBG("%s status %u", hdev->name, status);
5632
5633 hci_dev_lock(hdev);
5634
5635 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5636 if (!hci_cp)
5637 goto unlock;
5638
5639 if (hci_cp->which) {
5640 u16 handle = __le16_to_cpu(hci_cp->handle);
5641 conn = hci_conn_hash_lookup_handle(hdev, handle);
5642 } else {
5643 conn = NULL;
5644 }
5645
5646 cmd = mgmt_pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
5647 if (!cmd)
5648 goto unlock;
5649
Johan Hedberg69487372014-12-05 13:36:07 +02005650 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005651 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005652
5653unlock:
5654 hci_dev_unlock(hdev);
5655}
5656
5657static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5658 u16 len)
5659{
5660 struct mgmt_cp_get_clock_info *cp = data;
5661 struct mgmt_rp_get_clock_info rp;
5662 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005663 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005664 struct hci_request req;
5665 struct hci_conn *conn;
5666 int err;
5667
5668 BT_DBG("%s", hdev->name);
5669
5670 memset(&rp, 0, sizeof(rp));
5671 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5672 rp.addr.type = cp->addr.type;
5673
5674 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005675 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5676 MGMT_STATUS_INVALID_PARAMS,
5677 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005678
5679 hci_dev_lock(hdev);
5680
5681 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005682 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5683 MGMT_STATUS_NOT_POWERED, &rp,
5684 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005685 goto unlock;
5686 }
5687
5688 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5689 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5690 &cp->addr.bdaddr);
5691 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005692 err = mgmt_cmd_complete(sk, hdev->id,
5693 MGMT_OP_GET_CLOCK_INFO,
5694 MGMT_STATUS_NOT_CONNECTED,
5695 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005696 goto unlock;
5697 }
5698 } else {
5699 conn = NULL;
5700 }
5701
5702 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5703 if (!cmd) {
5704 err = -ENOMEM;
5705 goto unlock;
5706 }
5707
Johan Hedberg69487372014-12-05 13:36:07 +02005708 cmd->cmd_complete = clock_info_cmd_complete;
5709
Johan Hedberg95868422014-06-28 17:54:07 +03005710 hci_req_init(&req, hdev);
5711
5712 memset(&hci_cp, 0, sizeof(hci_cp));
5713 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5714
5715 if (conn) {
5716 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005717 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005718
5719 hci_cp.handle = cpu_to_le16(conn->handle);
5720 hci_cp.which = 0x01; /* Piconet clock */
5721 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5722 }
5723
5724 err = hci_req_run(&req, get_clock_info_complete);
5725 if (err < 0)
5726 mgmt_pending_remove(cmd);
5727
5728unlock:
5729 hci_dev_unlock(hdev);
5730 return err;
5731}
5732
Johan Hedberg5a154e62014-12-19 22:26:02 +02005733static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5734{
5735 struct hci_conn *conn;
5736
5737 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5738 if (!conn)
5739 return false;
5740
5741 if (conn->dst_type != type)
5742 return false;
5743
5744 if (conn->state != BT_CONNECTED)
5745 return false;
5746
5747 return true;
5748}
5749
5750/* This function requires the caller holds hdev->lock */
5751static int hci_conn_params_set(struct hci_request *req, bdaddr_t *addr,
5752 u8 addr_type, u8 auto_connect)
5753{
5754 struct hci_dev *hdev = req->hdev;
5755 struct hci_conn_params *params;
5756
5757 params = hci_conn_params_add(hdev, addr, addr_type);
5758 if (!params)
5759 return -EIO;
5760
5761 if (params->auto_connect == auto_connect)
5762 return 0;
5763
5764 list_del_init(&params->action);
5765
5766 switch (auto_connect) {
5767 case HCI_AUTO_CONN_DISABLED:
5768 case HCI_AUTO_CONN_LINK_LOSS:
5769 __hci_update_background_scan(req);
5770 break;
5771 case HCI_AUTO_CONN_REPORT:
5772 list_add(&params->action, &hdev->pend_le_reports);
5773 __hci_update_background_scan(req);
5774 break;
5775 case HCI_AUTO_CONN_DIRECT:
5776 case HCI_AUTO_CONN_ALWAYS:
5777 if (!is_connected(hdev, addr, addr_type)) {
5778 list_add(&params->action, &hdev->pend_le_conns);
5779 __hci_update_background_scan(req);
5780 }
5781 break;
5782 }
5783
5784 params->auto_connect = auto_connect;
5785
5786 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5787 auto_connect);
5788
5789 return 0;
5790}
5791
Marcel Holtmann8afef092014-06-29 22:28:34 +02005792static void device_added(struct sock *sk, struct hci_dev *hdev,
5793 bdaddr_t *bdaddr, u8 type, u8 action)
5794{
5795 struct mgmt_ev_device_added ev;
5796
5797 bacpy(&ev.addr.bdaddr, bdaddr);
5798 ev.addr.type = type;
5799 ev.action = action;
5800
5801 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5802}
5803
Marcel Holtmann1904a852015-01-11 13:50:44 -08005804static void add_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg5a154e62014-12-19 22:26:02 +02005805{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005806 struct mgmt_pending_cmd *cmd;
Johan Hedberg5a154e62014-12-19 22:26:02 +02005807
5808 BT_DBG("status 0x%02x", status);
5809
5810 hci_dev_lock(hdev);
5811
5812 cmd = mgmt_pending_find(MGMT_OP_ADD_DEVICE, hdev);
5813 if (!cmd)
5814 goto unlock;
5815
5816 cmd->cmd_complete(cmd, mgmt_status(status));
5817 mgmt_pending_remove(cmd);
5818
5819unlock:
5820 hci_dev_unlock(hdev);
5821}
5822
Marcel Holtmann2faade52014-06-29 19:44:03 +02005823static int add_device(struct sock *sk, struct hci_dev *hdev,
5824 void *data, u16 len)
5825{
5826 struct mgmt_cp_add_device *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005827 struct mgmt_pending_cmd *cmd;
Johan Hedberg5a154e62014-12-19 22:26:02 +02005828 struct hci_request req;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005829 u8 auto_conn, addr_type;
5830 int err;
5831
5832 BT_DBG("%s", hdev->name);
5833
Johan Hedberg66593582014-07-09 12:59:14 +03005834 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005835 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005836 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5837 MGMT_STATUS_INVALID_PARAMS,
5838 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005839
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005840 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005841 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5842 MGMT_STATUS_INVALID_PARAMS,
5843 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005844
Johan Hedberg5a154e62014-12-19 22:26:02 +02005845 hci_req_init(&req, hdev);
5846
Marcel Holtmann2faade52014-06-29 19:44:03 +02005847 hci_dev_lock(hdev);
5848
Johan Hedberg5a154e62014-12-19 22:26:02 +02005849 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_DEVICE, hdev, data, len);
5850 if (!cmd) {
5851 err = -ENOMEM;
5852 goto unlock;
5853 }
5854
5855 cmd->cmd_complete = addr_cmd_complete;
5856
Johan Hedberg66593582014-07-09 12:59:14 +03005857 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005858 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005859 if (cp->action != 0x01) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005860 err = cmd->cmd_complete(cmd,
5861 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005862 mgmt_pending_remove(cmd);
Johan Hedberg66593582014-07-09 12:59:14 +03005863 goto unlock;
5864 }
5865
5866 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5867 cp->addr.type);
5868 if (err)
5869 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005870
Johan Hedberg5a154e62014-12-19 22:26:02 +02005871 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03005872
Johan Hedberg66593582014-07-09 12:59:14 +03005873 goto added;
5874 }
5875
Marcel Holtmann2faade52014-06-29 19:44:03 +02005876 if (cp->addr.type == BDADDR_LE_PUBLIC)
5877 addr_type = ADDR_LE_DEV_PUBLIC;
5878 else
5879 addr_type = ADDR_LE_DEV_RANDOM;
5880
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005881 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005882 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005883 else if (cp->action == 0x01)
5884 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005885 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005886 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005887
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005888 /* If the connection parameters don't exist for this device,
5889 * they will be created and configured with defaults.
5890 */
Johan Hedberg5a154e62014-12-19 22:26:02 +02005891 if (hci_conn_params_set(&req, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005892 auto_conn) < 0) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005893 err = cmd->cmd_complete(cmd, MGMT_STATUS_FAILED);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005894 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005895 goto unlock;
5896 }
5897
Johan Hedberg66593582014-07-09 12:59:14 +03005898added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005899 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5900
Johan Hedberg5a154e62014-12-19 22:26:02 +02005901 err = hci_req_run(&req, add_device_complete);
5902 if (err < 0) {
5903 /* ENODATA means no HCI commands were needed (e.g. if
5904 * the adapter is powered off).
5905 */
Johan Hedberg9df74652014-12-19 22:26:03 +02005906 if (err == -ENODATA)
5907 err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005908 mgmt_pending_remove(cmd);
5909 }
Marcel Holtmann2faade52014-06-29 19:44:03 +02005910
5911unlock:
5912 hci_dev_unlock(hdev);
5913 return err;
5914}
5915
Marcel Holtmann8afef092014-06-29 22:28:34 +02005916static void device_removed(struct sock *sk, struct hci_dev *hdev,
5917 bdaddr_t *bdaddr, u8 type)
5918{
5919 struct mgmt_ev_device_removed ev;
5920
5921 bacpy(&ev.addr.bdaddr, bdaddr);
5922 ev.addr.type = type;
5923
5924 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5925}
5926
Marcel Holtmann1904a852015-01-11 13:50:44 -08005927static void remove_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005928{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005929 struct mgmt_pending_cmd *cmd;
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005930
5931 BT_DBG("status 0x%02x", status);
5932
5933 hci_dev_lock(hdev);
5934
5935 cmd = mgmt_pending_find(MGMT_OP_REMOVE_DEVICE, hdev);
5936 if (!cmd)
5937 goto unlock;
5938
5939 cmd->cmd_complete(cmd, mgmt_status(status));
5940 mgmt_pending_remove(cmd);
5941
5942unlock:
5943 hci_dev_unlock(hdev);
5944}
5945
Marcel Holtmann2faade52014-06-29 19:44:03 +02005946static int remove_device(struct sock *sk, struct hci_dev *hdev,
5947 void *data, u16 len)
5948{
5949 struct mgmt_cp_remove_device *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005950 struct mgmt_pending_cmd *cmd;
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005951 struct hci_request req;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005952 int err;
5953
5954 BT_DBG("%s", hdev->name);
5955
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005956 hci_req_init(&req, hdev);
5957
Marcel Holtmann2faade52014-06-29 19:44:03 +02005958 hci_dev_lock(hdev);
5959
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005960 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_DEVICE, hdev, data, len);
5961 if (!cmd) {
5962 err = -ENOMEM;
5963 goto unlock;
5964 }
5965
5966 cmd->cmd_complete = addr_cmd_complete;
5967
Marcel Holtmann2faade52014-06-29 19:44:03 +02005968 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03005969 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005970 u8 addr_type;
5971
Johan Hedberg66593582014-07-09 12:59:14 +03005972 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005973 err = cmd->cmd_complete(cmd,
5974 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005975 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005976 goto unlock;
5977 }
5978
Johan Hedberg66593582014-07-09 12:59:14 +03005979 if (cp->addr.type == BDADDR_BREDR) {
5980 err = hci_bdaddr_list_del(&hdev->whitelist,
5981 &cp->addr.bdaddr,
5982 cp->addr.type);
5983 if (err) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005984 err = cmd->cmd_complete(cmd,
5985 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005986 mgmt_pending_remove(cmd);
Johan Hedberg66593582014-07-09 12:59:14 +03005987 goto unlock;
5988 }
5989
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005990 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03005991
Johan Hedberg66593582014-07-09 12:59:14 +03005992 device_removed(sk, hdev, &cp->addr.bdaddr,
5993 cp->addr.type);
5994 goto complete;
5995 }
5996
Marcel Holtmann2faade52014-06-29 19:44:03 +02005997 if (cp->addr.type == BDADDR_LE_PUBLIC)
5998 addr_type = ADDR_LE_DEV_PUBLIC;
5999 else
6000 addr_type = ADDR_LE_DEV_RANDOM;
6001
Johan Hedbergc71593d2014-07-02 17:37:28 +03006002 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6003 addr_type);
6004 if (!params) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006005 err = cmd->cmd_complete(cmd,
6006 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006007 mgmt_pending_remove(cmd);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006008 goto unlock;
6009 }
6010
6011 if (params->auto_connect == HCI_AUTO_CONN_DISABLED) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006012 err = cmd->cmd_complete(cmd,
6013 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006014 mgmt_pending_remove(cmd);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006015 goto unlock;
6016 }
6017
Johan Hedbergd1dbf122014-07-04 16:17:23 +03006018 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006019 list_del(&params->list);
6020 kfree(params);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006021 __hci_update_background_scan(&req);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006022
6023 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006024 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03006025 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03006026 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03006027
Marcel Holtmann2faade52014-06-29 19:44:03 +02006028 if (cp->addr.type) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006029 err = cmd->cmd_complete(cmd,
6030 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006031 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006032 goto unlock;
6033 }
6034
Johan Hedberg66593582014-07-09 12:59:14 +03006035 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
6036 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
6037 list_del(&b->list);
6038 kfree(b);
6039 }
6040
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006041 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03006042
Johan Hedberg19de0822014-07-06 13:06:51 +03006043 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
6044 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
6045 continue;
6046 device_removed(sk, hdev, &p->addr, p->addr_type);
6047 list_del(&p->action);
6048 list_del(&p->list);
6049 kfree(p);
6050 }
6051
6052 BT_DBG("All LE connection parameters were removed");
6053
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006054 __hci_update_background_scan(&req);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006055 }
6056
Johan Hedberg66593582014-07-09 12:59:14 +03006057complete:
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006058 err = hci_req_run(&req, remove_device_complete);
6059 if (err < 0) {
6060 /* ENODATA means no HCI commands were needed (e.g. if
6061 * the adapter is powered off).
6062 */
Johan Hedberg9df74652014-12-19 22:26:03 +02006063 if (err == -ENODATA)
6064 err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006065 mgmt_pending_remove(cmd);
6066 }
Marcel Holtmann2faade52014-06-29 19:44:03 +02006067
6068unlock:
6069 hci_dev_unlock(hdev);
6070 return err;
6071}
6072
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006073static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
6074 u16 len)
6075{
6076 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006077 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
6078 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006079 u16 param_count, expected_len;
6080 int i;
6081
6082 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006083 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6084 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006085
6086 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006087 if (param_count > max_param_count) {
6088 BT_ERR("load_conn_param: too big param_count value %u",
6089 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006090 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6091 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006092 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006093
6094 expected_len = sizeof(*cp) + param_count *
6095 sizeof(struct mgmt_conn_param);
6096 if (expected_len != len) {
6097 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
6098 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006099 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6100 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006101 }
6102
6103 BT_DBG("%s param_count %u", hdev->name, param_count);
6104
6105 hci_dev_lock(hdev);
6106
6107 hci_conn_params_clear_disabled(hdev);
6108
6109 for (i = 0; i < param_count; i++) {
6110 struct mgmt_conn_param *param = &cp->params[i];
6111 struct hci_conn_params *hci_param;
6112 u16 min, max, latency, timeout;
6113 u8 addr_type;
6114
6115 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
6116 param->addr.type);
6117
6118 if (param->addr.type == BDADDR_LE_PUBLIC) {
6119 addr_type = ADDR_LE_DEV_PUBLIC;
6120 } else if (param->addr.type == BDADDR_LE_RANDOM) {
6121 addr_type = ADDR_LE_DEV_RANDOM;
6122 } else {
6123 BT_ERR("Ignoring invalid connection parameters");
6124 continue;
6125 }
6126
6127 min = le16_to_cpu(param->min_interval);
6128 max = le16_to_cpu(param->max_interval);
6129 latency = le16_to_cpu(param->latency);
6130 timeout = le16_to_cpu(param->timeout);
6131
6132 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6133 min, max, latency, timeout);
6134
6135 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
6136 BT_ERR("Ignoring invalid connection parameters");
6137 continue;
6138 }
6139
6140 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
6141 addr_type);
6142 if (!hci_param) {
6143 BT_ERR("Failed to add connection parameters");
6144 continue;
6145 }
6146
6147 hci_param->conn_min_interval = min;
6148 hci_param->conn_max_interval = max;
6149 hci_param->conn_latency = latency;
6150 hci_param->supervision_timeout = timeout;
6151 }
6152
6153 hci_dev_unlock(hdev);
6154
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006155 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
6156 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006157}
6158
Marcel Holtmanndbece372014-07-04 18:11:55 +02006159static int set_external_config(struct sock *sk, struct hci_dev *hdev,
6160 void *data, u16 len)
6161{
6162 struct mgmt_cp_set_external_config *cp = data;
6163 bool changed;
6164 int err;
6165
6166 BT_DBG("%s", hdev->name);
6167
6168 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006169 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6170 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006171
6172 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006173 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6174 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006175
6176 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02006177 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6178 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006179
6180 hci_dev_lock(hdev);
6181
6182 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07006183 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006184 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006185 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006186
6187 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
6188 if (err < 0)
6189 goto unlock;
6190
6191 if (!changed)
6192 goto unlock;
6193
Marcel Holtmannf4537c02014-07-04 19:06:23 +02006194 err = new_options(hdev, sk);
6195
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006196 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02006197 mgmt_index_removed(hdev);
Marcel Holtmannd603b762014-07-06 12:11:14 +02006198
Marcel Holtmann516018a2015-03-13 02:11:04 -07006199 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006200 hci_dev_set_flag(hdev, HCI_CONFIG);
6201 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b762014-07-06 12:11:14 +02006202
6203 queue_work(hdev->req_workqueue, &hdev->power_on);
6204 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02006205 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b762014-07-06 12:11:14 +02006206 mgmt_index_added(hdev);
6207 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02006208 }
6209
6210unlock:
6211 hci_dev_unlock(hdev);
6212 return err;
6213}
6214
Marcel Holtmann9713c172014-07-06 12:11:15 +02006215static int set_public_address(struct sock *sk, struct hci_dev *hdev,
6216 void *data, u16 len)
6217{
6218 struct mgmt_cp_set_public_address *cp = data;
6219 bool changed;
6220 int err;
6221
6222 BT_DBG("%s", hdev->name);
6223
6224 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006225 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6226 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006227
6228 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02006229 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6230 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006231
6232 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02006233 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6234 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006235
6236 hci_dev_lock(hdev);
6237
6238 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
6239 bacpy(&hdev->public_addr, &cp->bdaddr);
6240
6241 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
6242 if (err < 0)
6243 goto unlock;
6244
6245 if (!changed)
6246 goto unlock;
6247
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006248 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006249 err = new_options(hdev, sk);
6250
6251 if (is_configured(hdev)) {
6252 mgmt_index_removed(hdev);
6253
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006254 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006255
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006256 hci_dev_set_flag(hdev, HCI_CONFIG);
6257 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006258
6259 queue_work(hdev->req_workqueue, &hdev->power_on);
6260 }
6261
6262unlock:
6263 hci_dev_unlock(hdev);
6264 return err;
6265}
6266
Marcel Holtmannbea41602015-03-14 22:43:17 -07006267static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
6268 u8 data_len)
6269{
6270 eir[eir_len++] = sizeof(type) + data_len;
6271 eir[eir_len++] = type;
6272 memcpy(&eir[eir_len], data, data_len);
6273 eir_len += data_len;
6274
6275 return eir_len;
6276}
6277
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006278static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
6279 void *data, u16 data_len)
6280{
6281 struct mgmt_cp_read_local_oob_ext_data *cp = data;
6282 struct mgmt_rp_read_local_oob_ext_data *rp;
6283 size_t rp_len;
6284 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006285 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006286 int err;
6287
6288 BT_DBG("%s", hdev->name);
6289
6290 if (!hdev_is_powered(hdev))
6291 return mgmt_cmd_complete(sk, hdev->id,
6292 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6293 MGMT_STATUS_NOT_POWERED,
6294 &cp->type, sizeof(cp->type));
6295
6296 switch (cp->type) {
6297 case BIT(BDADDR_BREDR):
6298 status = mgmt_bredr_support(hdev);
6299 if (status)
6300 return mgmt_cmd_complete(sk, hdev->id,
6301 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6302 status, &cp->type,
6303 sizeof(cp->type));
6304 eir_len = 5;
6305 break;
6306 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6307 status = mgmt_le_support(hdev);
6308 if (status)
6309 return mgmt_cmd_complete(sk, hdev->id,
6310 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6311 status, &cp->type,
6312 sizeof(cp->type));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006313 eir_len = 9 + 3 + 18 + 18 + 3;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006314 break;
6315 default:
6316 return mgmt_cmd_complete(sk, hdev->id,
6317 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6318 MGMT_STATUS_INVALID_PARAMS,
6319 &cp->type, sizeof(cp->type));
6320 }
6321
6322 hci_dev_lock(hdev);
6323
6324 rp_len = sizeof(*rp) + eir_len;
6325 rp = kmalloc(rp_len, GFP_ATOMIC);
6326 if (!rp) {
6327 hci_dev_unlock(hdev);
6328 return -ENOMEM;
6329 }
6330
6331 eir_len = 0;
6332 switch (cp->type) {
6333 case BIT(BDADDR_BREDR):
6334 eir_len = eir_append_data(rp->eir, eir_len, EIR_CLASS_OF_DEV,
6335 hdev->dev_class, 3);
6336 break;
6337 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07006338 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6339 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006340 hci_dev_unlock(hdev);
6341 err = mgmt_cmd_complete(sk, hdev->id,
Marcel Holtmann5082a592015-03-16 12:39:00 -07006342 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6343 MGMT_STATUS_FAILED,
6344 &cp->type, sizeof(cp->type));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006345 goto done;
6346 }
6347
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006348 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
6349 memcpy(addr, &hdev->rpa, 6);
6350 addr[6] = 0x01;
6351 } else if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
6352 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
6353 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
6354 bacmp(&hdev->static_addr, BDADDR_ANY))) {
6355 memcpy(addr, &hdev->static_addr, 6);
6356 addr[6] = 0x01;
6357 } else {
6358 memcpy(addr, &hdev->bdaddr, 6);
6359 addr[6] = 0x00;
6360 }
6361
6362 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
6363 addr, sizeof(addr));
6364
6365 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
6366 role = 0x02;
6367 else
6368 role = 0x01;
6369
6370 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
6371 &role, sizeof(role));
6372
Marcel Holtmann5082a592015-03-16 12:39:00 -07006373 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
6374 eir_len = eir_append_data(rp->eir, eir_len,
6375 EIR_LE_SC_CONFIRM,
6376 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006377
Marcel Holtmann5082a592015-03-16 12:39:00 -07006378 eir_len = eir_append_data(rp->eir, eir_len,
6379 EIR_LE_SC_RANDOM,
6380 rand, sizeof(rand));
6381 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006382
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006383 flags = get_adv_discov_flags(hdev);
6384
6385 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
6386 flags |= LE_AD_NO_BREDR;
6387
6388 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
6389 &flags, sizeof(flags));
6390 break;
6391 }
6392
6393 rp->type = cp->type;
6394 rp->eir_len = cpu_to_le16(eir_len);
6395
6396 hci_dev_unlock(hdev);
6397
Marcel Holtmann72000df2015-03-16 16:11:21 -07006398 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
6399
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006400 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann5425f982015-03-16 16:05:44 -07006401 MGMT_STATUS_SUCCESS, rp, sizeof(*rp) + eir_len);
Marcel Holtmann72000df2015-03-16 16:11:21 -07006402 if (err < 0)
6403 goto done;
6404
6405 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6406 rp, sizeof(*rp) + eir_len,
6407 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006408
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006409done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006410 kfree(rp);
6411
6412 return err;
6413}
6414
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006415static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6416 void *data, u16 data_len)
6417{
6418 struct mgmt_rp_read_adv_features *rp;
6419 size_t rp_len;
6420 int err;
6421
6422 BT_DBG("%s", hdev->name);
6423
6424 hci_dev_lock(hdev);
6425
6426 rp_len = sizeof(*rp);
6427 rp = kmalloc(rp_len, GFP_ATOMIC);
6428 if (!rp) {
6429 hci_dev_unlock(hdev);
6430 return -ENOMEM;
6431 }
6432
6433 rp->supported_flags = cpu_to_le32(0);
6434 rp->max_adv_data_len = 31;
6435 rp->max_scan_rsp_len = 31;
6436 rp->max_instances = 0;
6437 rp->num_instances = 0;
6438
6439 hci_dev_unlock(hdev);
6440
6441 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6442 MGMT_STATUS_SUCCESS, rp, rp_len);
6443
6444 kfree(rp);
6445
6446 return err;
6447}
6448
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006449static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006450 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006451 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006452 HCI_MGMT_NO_HDEV |
6453 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006454 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006455 HCI_MGMT_NO_HDEV |
6456 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006457 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006458 HCI_MGMT_NO_HDEV |
6459 HCI_MGMT_UNTRUSTED },
6460 { read_controller_info, MGMT_READ_INFO_SIZE,
6461 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006462 { set_powered, MGMT_SETTING_SIZE },
6463 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6464 { set_connectable, MGMT_SETTING_SIZE },
6465 { set_fast_connectable, MGMT_SETTING_SIZE },
6466 { set_bondable, MGMT_SETTING_SIZE },
6467 { set_link_security, MGMT_SETTING_SIZE },
6468 { set_ssp, MGMT_SETTING_SIZE },
6469 { set_hs, MGMT_SETTING_SIZE },
6470 { set_le, MGMT_SETTING_SIZE },
6471 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6472 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6473 { add_uuid, MGMT_ADD_UUID_SIZE },
6474 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006475 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6476 HCI_MGMT_VAR_LEN },
6477 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6478 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006479 { disconnect, MGMT_DISCONNECT_SIZE },
6480 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6481 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6482 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6483 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6484 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6485 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6486 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6487 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6488 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6489 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6490 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006491 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6492 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6493 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006494 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6495 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6496 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6497 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6498 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6499 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6500 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6501 { set_advertising, MGMT_SETTING_SIZE },
6502 { set_bredr, MGMT_SETTING_SIZE },
6503 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6504 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6505 { set_secure_conn, MGMT_SETTING_SIZE },
6506 { set_debug_keys, MGMT_SETTING_SIZE },
6507 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006508 { load_irks, MGMT_LOAD_IRKS_SIZE,
6509 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006510 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6511 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6512 { add_device, MGMT_ADD_DEVICE_SIZE },
6513 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006514 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6515 HCI_MGMT_VAR_LEN },
6516 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006517 HCI_MGMT_NO_HDEV |
6518 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006519 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006520 HCI_MGMT_UNCONFIGURED |
6521 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006522 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6523 HCI_MGMT_UNCONFIGURED },
6524 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6525 HCI_MGMT_UNCONFIGURED },
6526 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6527 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006528 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006529 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006530 HCI_MGMT_NO_HDEV |
6531 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006532 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006533};
6534
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006535int mgmt_control(struct hci_mgmt_chan *chan, struct sock *sk,
6536 struct msghdr *msg, size_t msglen)
Johan Hedberg03811012010-12-08 00:21:06 +02006537{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03006538 void *buf;
6539 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02006540 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01006541 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006542 struct hci_dev *hdev = NULL;
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006543 const struct hci_mgmt_handler *handler;
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006544 bool var_len, no_hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02006545 int err;
6546
6547 BT_DBG("got %zu bytes", msglen);
6548
6549 if (msglen < sizeof(*hdr))
6550 return -EINVAL;
6551
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03006552 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02006553 if (!buf)
6554 return -ENOMEM;
6555
Al Viro6ce8e9c2014-04-06 21:25:44 -04006556 if (memcpy_from_msg(buf, msg, msglen)) {
Johan Hedberg03811012010-12-08 00:21:06 +02006557 err = -EFAULT;
6558 goto done;
6559 }
6560
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03006561 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07006562 opcode = __le16_to_cpu(hdr->opcode);
6563 index = __le16_to_cpu(hdr->index);
6564 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02006565
6566 if (len != msglen - sizeof(*hdr)) {
6567 err = -EINVAL;
6568 goto done;
6569 }
6570
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006571 if (opcode >= chan->handler_count ||
6572 chan->handlers[opcode].func == NULL) {
6573 BT_DBG("Unknown op %u", opcode);
Johan Hedberga69e8372015-03-06 21:08:53 +02006574 err = mgmt_cmd_status(sk, index, opcode,
6575 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006576 goto done;
6577 }
6578
6579 handler = &chan->handlers[opcode];
6580
Marcel Holtmannc927a102015-03-14 19:28:03 -07006581 if (!hci_sock_test_flag(sk, HCI_SOCK_TRUSTED) &&
6582 !(handler->flags & HCI_MGMT_UNTRUSTED)) {
6583 err = mgmt_cmd_status(sk, index, opcode,
6584 MGMT_STATUS_PERMISSION_DENIED);
6585 goto done;
6586 }
6587
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006588 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006589 hdev = hci_dev_get(index);
6590 if (!hdev) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006591 err = mgmt_cmd_status(sk, index, opcode,
6592 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006593 goto done;
6594 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07006595
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006596 if (hci_dev_test_flag(hdev, HCI_SETUP) ||
6597 hci_dev_test_flag(hdev, HCI_CONFIG) ||
6598 hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006599 err = mgmt_cmd_status(sk, index, opcode,
6600 MGMT_STATUS_INVALID_INDEX);
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07006601 goto done;
6602 }
Marcel Holtmann42a9bc142014-07-04 16:54:40 +02006603
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006604 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006605 !(handler->flags & HCI_MGMT_UNCONFIGURED)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006606 err = mgmt_cmd_status(sk, index, opcode,
6607 MGMT_STATUS_INVALID_INDEX);
Marcel Holtmann42a9bc142014-07-04 16:54:40 +02006608 goto done;
6609 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006610 }
6611
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006612 no_hdev = (handler->flags & HCI_MGMT_NO_HDEV);
6613 if (no_hdev != !hdev) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006614 err = mgmt_cmd_status(sk, index, opcode,
6615 MGMT_STATUS_INVALID_INDEX);
Marcel Holtmann73d1df22014-07-02 22:10:52 +02006616 goto done;
6617 }
6618
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006619 var_len = (handler->flags & HCI_MGMT_VAR_LEN);
6620 if ((var_len && len < handler->data_len) ||
6621 (!var_len && len != handler->data_len)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006622 err = mgmt_cmd_status(sk, index, opcode,
6623 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02006624 goto done;
6625 }
6626
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006627 if (hdev)
6628 mgmt_init_hdev(sk, hdev);
6629
6630 cp = buf + sizeof(*hdr);
6631
Johan Hedbergbe22b542012-03-01 22:24:41 +02006632 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02006633 if (err < 0)
6634 goto done;
6635
Johan Hedberg03811012010-12-08 00:21:06 +02006636 err = msglen;
6637
6638done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006639 if (hdev)
6640 hci_dev_put(hdev);
6641
Johan Hedberg03811012010-12-08 00:21:06 +02006642 kfree(buf);
6643 return err;
6644}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006645
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006646void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006647{
Marcel Holtmannced85542015-03-14 19:27:56 -07006648 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006649
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006650 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6651 return;
6652
Marcel Holtmannf9207332015-03-14 19:27:55 -07006653 switch (hdev->dev_type) {
6654 case HCI_BREDR:
6655 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6656 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6657 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006658 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006659 } else {
6660 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6661 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006662 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006663 }
6664 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006665 case HCI_AMP:
6666 ev.type = 0x02;
6667 break;
6668 default:
6669 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006670 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006671
6672 ev.bus = hdev->bus;
6673
6674 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6675 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006676}
6677
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006678void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006679{
Marcel Holtmannced85542015-03-14 19:27:56 -07006680 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006681 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006682
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006683 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6684 return;
6685
Marcel Holtmannf9207332015-03-14 19:27:55 -07006686 switch (hdev->dev_type) {
6687 case HCI_BREDR:
6688 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006689
Marcel Holtmannf9207332015-03-14 19:27:55 -07006690 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6691 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6692 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006693 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006694 } else {
6695 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6696 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006697 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006698 }
6699 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006700 case HCI_AMP:
6701 ev.type = 0x02;
6702 break;
6703 default:
6704 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006705 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006706
6707 ev.bus = hdev->bus;
6708
6709 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6710 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006711}
6712
Andre Guedes6046dc32014-02-26 20:21:51 -03006713/* This function requires the caller holds hdev->lock */
Johan Hedberg2cf22212014-12-19 22:26:00 +02006714static void restart_le_actions(struct hci_request *req)
Andre Guedes6046dc32014-02-26 20:21:51 -03006715{
Johan Hedberg2cf22212014-12-19 22:26:00 +02006716 struct hci_dev *hdev = req->hdev;
Andre Guedes6046dc32014-02-26 20:21:51 -03006717 struct hci_conn_params *p;
6718
6719 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006720 /* Needed for AUTO_OFF case where might not "really"
6721 * have been powered off.
6722 */
6723 list_del_init(&p->action);
6724
6725 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006726 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006727 case HCI_AUTO_CONN_ALWAYS:
6728 list_add(&p->action, &hdev->pend_le_conns);
6729 break;
6730 case HCI_AUTO_CONN_REPORT:
6731 list_add(&p->action, &hdev->pend_le_reports);
6732 break;
6733 default:
6734 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006735 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006736 }
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006737
Johan Hedberg2cf22212014-12-19 22:26:00 +02006738 __hci_update_background_scan(req);
Andre Guedes6046dc32014-02-26 20:21:51 -03006739}
6740
Marcel Holtmann1904a852015-01-11 13:50:44 -08006741static void powered_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg229ab392013-03-15 17:06:53 -05006742{
6743 struct cmd_lookup match = { NULL, hdev };
6744
6745 BT_DBG("status 0x%02x", status);
6746
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006747 if (!status) {
6748 /* Register the available SMP channels (BR/EDR and LE) only
6749 * when successfully powering on the controller. This late
6750 * registration is required so that LE SMP can clearly
6751 * decide if the public address or static address is used.
6752 */
6753 smp_register(hdev);
6754 }
6755
Johan Hedberg229ab392013-03-15 17:06:53 -05006756 hci_dev_lock(hdev);
6757
6758 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6759
6760 new_settings(hdev, match.sk);
6761
6762 hci_dev_unlock(hdev);
6763
6764 if (match.sk)
6765 sock_put(match.sk);
6766}
6767
Johan Hedberg70da6242013-03-15 17:06:51 -05006768static int powered_update_hci(struct hci_dev *hdev)
6769{
Johan Hedberg890ea892013-03-15 17:06:52 -05006770 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05006771 u8 link_sec;
6772
Johan Hedberg890ea892013-03-15 17:06:52 -05006773 hci_req_init(&req, hdev);
6774
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006775 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED) &&
Johan Hedberg70da6242013-03-15 17:06:51 -05006776 !lmp_host_ssp_capable(hdev)) {
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006777 u8 mode = 0x01;
Johan Hedberg70da6242013-03-15 17:06:51 -05006778
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006779 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
Johan Hedberg70da6242013-03-15 17:06:51 -05006780
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006781 if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) {
6782 u8 support = 0x01;
6783
6784 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT,
6785 sizeof(support), &support);
6786 }
Johan Hedbergec6f99b2014-12-12 13:30:11 +02006787 }
6788
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006789 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
Johan Hedbergc73eee92013-04-19 18:35:21 +03006790 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05006791 struct hci_cp_write_le_host_supported cp;
6792
Marcel Holtmann32226e42014-07-24 20:04:16 +02006793 cp.le = 0x01;
6794 cp.simul = 0x00;
Johan Hedberg70da6242013-03-15 17:06:51 -05006795
6796 /* Check first if we already have the right
6797 * host state (host features set)
6798 */
6799 if (cp.le != lmp_host_le_capable(hdev) ||
6800 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05006801 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
6802 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05006803 }
6804
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07006805 if (lmp_le_capable(hdev)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006806 /* Make sure the controller has a good default for
6807 * advertising data. This also applies to the case
6808 * where BR/EDR was toggled during the AUTO_OFF phase.
6809 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006810 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07006811 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07006812 update_scan_rsp_data(&req);
6813 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006814
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006815 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07006816 enable_advertising(&req);
Johan Hedberg2cf22212014-12-19 22:26:00 +02006817
6818 restart_le_actions(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03006819 }
6820
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006821 link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg70da6242013-03-15 17:06:51 -05006822 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05006823 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
6824 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05006825
6826 if (lmp_bredr_capable(hdev)) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006827 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg406ef2a2015-03-10 20:14:27 +02006828 write_fast_connectable(&req, true);
6829 else
6830 write_fast_connectable(&req, false);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02006831 __hci_update_page_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006832 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05006833 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006834 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05006835 }
6836
Johan Hedberg229ab392013-03-15 17:06:53 -05006837 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05006838}
6839
Johan Hedberg744cf192011-11-08 20:40:14 +02006840int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006841{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006842 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006843 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006844 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006845
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006846 if (!hci_dev_test_flag(hdev, HCI_MGMT))
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006847 return 0;
6848
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006849 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05006850 if (powered_update_hci(hdev) == 0)
6851 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02006852
Johan Hedberg229ab392013-03-15 17:06:53 -05006853 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
6854 &match);
6855 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006856 }
6857
Johan Hedberg229ab392013-03-15 17:06:53 -05006858 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006859
6860 /* If the power off is because of hdev unregistration let
6861 * use the appropriate INVALID_INDEX status. Otherwise use
6862 * NOT_POWERED. We cover both scenarios here since later in
6863 * mgmt_index_removed() any hci_conn callbacks will have already
6864 * been triggered, potentially causing misleading DISCONNECTED
6865 * status responses.
6866 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006867 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006868 status = MGMT_STATUS_INVALID_INDEX;
6869 else
6870 status = MGMT_STATUS_NOT_POWERED;
6871
6872 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006873
6874 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07006875 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6876 zero_cod, sizeof(zero_cod), NULL);
Johan Hedberg229ab392013-03-15 17:06:53 -05006877
6878new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02006879 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006880
6881 if (match.sk)
6882 sock_put(match.sk);
6883
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006884 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006885}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006886
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006887void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006888{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006889 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006890 u8 status;
6891
6892 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
6893 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006894 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006895
6896 if (err == -ERFKILL)
6897 status = MGMT_STATUS_RFKILLED;
6898 else
6899 status = MGMT_STATUS_FAILED;
6900
Johan Hedberga69e8372015-03-06 21:08:53 +02006901 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006902
6903 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006904}
6905
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006906void mgmt_discoverable_timeout(struct hci_dev *hdev)
6907{
6908 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006909
6910 hci_dev_lock(hdev);
6911
6912 /* When discoverable timeout triggers, then just make sure
6913 * the limited discoverable flag is cleared. Even in the case
6914 * of a timeout triggered from general discoverable, it is
6915 * safe to unconditionally clear the flag.
6916 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006917 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
6918 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006919
6920 hci_req_init(&req, hdev);
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006921 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg4b580612013-10-19 23:38:21 +03006922 u8 scan = SCAN_PAGE;
6923 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
6924 sizeof(scan), &scan);
6925 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006926 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03006927 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006928 hci_req_run(&req, NULL);
6929
6930 hdev->discov_timeout = 0;
6931
Johan Hedberg9a43e252013-10-20 19:00:07 +03006932 new_settings(hdev, NULL);
6933
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006934 hci_dev_unlock(hdev);
6935}
6936
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006937void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
6938 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006939{
Johan Hedberg86742e12011-11-07 23:13:38 +02006940 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006941
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006942 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006943
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006944 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02006945 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006946 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006947 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03006948 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006949 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006950
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006951 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006952}
Johan Hedbergf7520542011-01-20 12:34:39 +02006953
Johan Hedbergd7b25452014-05-23 13:19:53 +03006954static u8 mgmt_ltk_type(struct smp_ltk *ltk)
6955{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03006956 switch (ltk->type) {
6957 case SMP_LTK:
6958 case SMP_LTK_SLAVE:
6959 if (ltk->authenticated)
6960 return MGMT_LTK_AUTHENTICATED;
6961 return MGMT_LTK_UNAUTHENTICATED;
6962 case SMP_LTK_P256:
6963 if (ltk->authenticated)
6964 return MGMT_LTK_P256_AUTH;
6965 return MGMT_LTK_P256_UNAUTH;
6966 case SMP_LTK_P256_DEBUG:
6967 return MGMT_LTK_P256_DEBUG;
6968 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03006969
6970 return MGMT_LTK_UNAUTHENTICATED;
6971}
6972
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006973void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006974{
6975 struct mgmt_ev_new_long_term_key ev;
6976
6977 memset(&ev, 0, sizeof(ev));
6978
Marcel Holtmann5192d302014-02-19 17:11:58 -08006979 /* Devices using resolvable or non-resolvable random addresses
6980 * without providing an indentity resolving key don't require
6981 * to store long term keys. Their addresses will change the
6982 * next time around.
6983 *
6984 * Only when a remote device provides an identity address
6985 * make sure the long term key is stored. If the remote
6986 * identity is known, the long term keys are internally
6987 * mapped to the identity address. So allow static random
6988 * and public addresses here.
6989 */
Johan Hedbergba74b662014-02-19 14:57:45 +02006990 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
6991 (key->bdaddr.b[5] & 0xc0) != 0xc0)
6992 ev.store_hint = 0x00;
6993 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07006994 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02006995
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006996 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03006997 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03006998 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03006999 ev.key.enc_size = key->enc_size;
7000 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08007001 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007002
Johan Hedberg2ceba532014-06-16 19:25:16 +03007003 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007004 ev.key.master = 1;
7005
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007006 memcpy(ev.key.val, key->val, sizeof(key->val));
7007
Marcel Holtmann083368f2013-10-15 14:26:29 -07007008 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007009}
7010
Johan Hedberg95fbac82014-02-19 15:18:31 +02007011void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk)
7012{
7013 struct mgmt_ev_new_irk ev;
7014
7015 memset(&ev, 0, sizeof(ev));
7016
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08007017 /* For identity resolving keys from devices that are already
7018 * using a public address or static random address, do not
7019 * ask for storing this key. The identity resolving key really
7020 * is only mandatory for devices using resovlable random
7021 * addresses.
7022 *
7023 * Storing all identity resolving keys has the downside that
7024 * they will be also loaded on next boot of they system. More
7025 * identity resolving keys, means more time during scanning is
7026 * needed to actually resolve these addresses.
7027 */
7028 if (bacmp(&irk->rpa, BDADDR_ANY))
7029 ev.store_hint = 0x01;
7030 else
7031 ev.store_hint = 0x00;
7032
Johan Hedberg95fbac82014-02-19 15:18:31 +02007033 bacpy(&ev.rpa, &irk->rpa);
7034 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
7035 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
7036 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
7037
7038 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
7039}
7040
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007041void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
7042 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007043{
7044 struct mgmt_ev_new_csrk ev;
7045
7046 memset(&ev, 0, sizeof(ev));
7047
7048 /* Devices using resolvable or non-resolvable random addresses
7049 * without providing an indentity resolving key don't require
7050 * to store signature resolving keys. Their addresses will change
7051 * the next time around.
7052 *
7053 * Only when a remote device provides an identity address
7054 * make sure the signature resolving key is stored. So allow
7055 * static random and public addresses here.
7056 */
7057 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7058 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
7059 ev.store_hint = 0x00;
7060 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007061 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007062
7063 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
7064 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02007065 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007066 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
7067
7068 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
7069}
7070
Andre Guedesffb5a8272014-07-01 18:10:11 -03007071void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03007072 u8 bdaddr_type, u8 store_hint, u16 min_interval,
7073 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03007074{
7075 struct mgmt_ev_new_conn_param ev;
7076
Johan Hedbergc103aea2014-07-02 17:37:34 +03007077 if (!hci_is_identity_address(bdaddr, bdaddr_type))
7078 return;
7079
Andre Guedesffb5a8272014-07-01 18:10:11 -03007080 memset(&ev, 0, sizeof(ev));
7081 bacpy(&ev.addr.bdaddr, bdaddr);
7082 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03007083 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03007084 ev.min_interval = cpu_to_le16(min_interval);
7085 ev.max_interval = cpu_to_le16(max_interval);
7086 ev.latency = cpu_to_le16(latency);
7087 ev.timeout = cpu_to_le16(timeout);
7088
7089 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
7090}
7091
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007092void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
7093 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02007094{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007095 char buf[512];
7096 struct mgmt_ev_device_connected *ev = (void *) buf;
7097 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02007098
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007099 bacpy(&ev->addr.bdaddr, &conn->dst);
7100 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02007101
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02007102 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02007103
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007104 /* We must ensure that the EIR Data fields are ordered and
7105 * unique. Keep it simple for now and avoid the problem by not
7106 * adding any BR/EDR data to the LE adv.
7107 */
7108 if (conn->le_adv_data_len > 0) {
7109 memcpy(&ev->eir[eir_len],
7110 conn->le_adv_data, conn->le_adv_data_len);
7111 eir_len = conn->le_adv_data_len;
7112 } else {
7113 if (name_len > 0)
7114 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
7115 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007116
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00007117 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007118 eir_len = eir_append_data(ev->eir, eir_len,
7119 EIR_CLASS_OF_DEV,
7120 conn->dev_class, 3);
7121 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02007122
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007123 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007124
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07007125 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
7126 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02007127}
7128
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007129static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007130{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007131 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007132
Johan Hedbergf5818c22014-12-05 13:36:02 +02007133 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007134
7135 *sk = cmd->sk;
7136 sock_hold(*sk);
7137
Johan Hedberga664b5b2011-02-19 12:06:02 -03007138 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007139}
7140
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007141static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007142{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007143 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007144 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007145
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007146 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7147
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007148 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007149 mgmt_pending_remove(cmd);
7150}
7151
Johan Hedberg84c61d92014-08-01 11:13:30 +03007152bool mgmt_powering_down(struct hci_dev *hdev)
7153{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007154 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007155 struct mgmt_mode *cp;
7156
7157 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
7158 if (!cmd)
7159 return false;
7160
7161 cp = cmd->param;
7162 if (!cp->val)
7163 return true;
7164
7165 return false;
7166}
7167
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007168void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007169 u8 link_type, u8 addr_type, u8 reason,
7170 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007171{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007172 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007173 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007174
Johan Hedberg84c61d92014-08-01 11:13:30 +03007175 /* The connection is still in hci_conn_hash so test for 1
7176 * instead of 0 to know if this is the last one.
7177 */
7178 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7179 cancel_delayed_work(&hdev->power_off);
7180 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007181 }
7182
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007183 if (!mgmt_connected)
7184 return;
7185
Andre Guedes57eb7762013-10-30 19:01:41 -03007186 if (link_type != ACL_LINK && link_type != LE_LINK)
7187 return;
7188
Johan Hedberg744cf192011-11-08 20:40:14 +02007189 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007190
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007191 bacpy(&ev.addr.bdaddr, bdaddr);
7192 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7193 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007194
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007195 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007196
7197 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007198 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007199
Johan Hedberg124f6e32012-02-09 13:50:12 +02007200 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007201 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007202}
7203
Marcel Holtmann78929242013-10-06 23:55:47 -07007204void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7205 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007206{
Andre Guedes3655bba2013-10-30 19:01:40 -03007207 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7208 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007209 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007210
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007211 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7212 hdev);
7213
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007214 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007215 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007216 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007217
Andre Guedes3655bba2013-10-30 19:01:40 -03007218 cp = cmd->param;
7219
7220 if (bacmp(bdaddr, &cp->addr.bdaddr))
7221 return;
7222
7223 if (cp->addr.type != bdaddr_type)
7224 return;
7225
Johan Hedbergf5818c22014-12-05 13:36:02 +02007226 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007227 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007228}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007229
Marcel Holtmann445608d2013-10-06 23:55:48 -07007230void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7231 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007232{
7233 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007234
Johan Hedberg84c61d92014-08-01 11:13:30 +03007235 /* The connection is still in hci_conn_hash so test for 1
7236 * instead of 0 to know if this is the last one.
7237 */
7238 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7239 cancel_delayed_work(&hdev->power_off);
7240 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007241 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007242
Johan Hedberg4c659c32011-11-07 23:13:39 +02007243 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007244 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007245 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007246
Marcel Holtmann445608d2013-10-06 23:55:48 -07007247 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007248}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007249
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007250void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007251{
7252 struct mgmt_ev_pin_code_request ev;
7253
Johan Hedbergd8457692012-02-17 14:24:57 +02007254 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007255 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007256 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007257
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007258 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007259}
7260
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007261void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7262 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007263{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007264 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007265
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007266 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007267 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007268 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007269
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007270 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007271 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007272}
7273
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007274void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7275 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007276{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007277 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007278
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007279 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007280 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007281 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007282
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007283 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007284 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007285}
Johan Hedberga5c29682011-02-19 12:05:57 -03007286
Johan Hedberg744cf192011-11-08 20:40:14 +02007287int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007288 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007289 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007290{
7291 struct mgmt_ev_user_confirm_request ev;
7292
Johan Hedberg744cf192011-11-08 20:40:14 +02007293 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007294
Johan Hedberg272d90d2012-02-09 15:26:12 +02007295 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007296 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007297 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007298 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007299
Johan Hedberg744cf192011-11-08 20:40:14 +02007300 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007301 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007302}
7303
Johan Hedberg272d90d2012-02-09 15:26:12 +02007304int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007305 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007306{
7307 struct mgmt_ev_user_passkey_request ev;
7308
7309 BT_DBG("%s", hdev->name);
7310
Johan Hedberg272d90d2012-02-09 15:26:12 +02007311 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007312 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007313
7314 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007315 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007316}
7317
Brian Gix0df4c182011-11-16 13:53:13 -08007318static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007319 u8 link_type, u8 addr_type, u8 status,
7320 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007321{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007322 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007323
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007324 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007325 if (!cmd)
7326 return -ENOENT;
7327
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007328 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007329 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007330
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007331 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007332}
7333
Johan Hedberg744cf192011-11-08 20:40:14 +02007334int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007335 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007336{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007337 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007338 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007339}
7340
Johan Hedberg272d90d2012-02-09 15:26:12 +02007341int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007342 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007343{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007344 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007345 status,
7346 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007347}
Johan Hedberg2a611692011-02-19 12:06:00 -03007348
Brian Gix604086b2011-11-23 08:28:33 -08007349int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007350 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007351{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007352 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007353 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007354}
7355
Johan Hedberg272d90d2012-02-09 15:26:12 +02007356int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007357 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007358{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007359 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007360 status,
7361 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007362}
7363
Johan Hedberg92a25252012-09-06 18:39:26 +03007364int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7365 u8 link_type, u8 addr_type, u32 passkey,
7366 u8 entered)
7367{
7368 struct mgmt_ev_passkey_notify ev;
7369
7370 BT_DBG("%s", hdev->name);
7371
7372 bacpy(&ev.addr.bdaddr, bdaddr);
7373 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7374 ev.passkey = __cpu_to_le32(passkey);
7375 ev.entered = entered;
7376
7377 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7378}
7379
Johan Hedberge1e930f2014-09-08 17:09:49 -07007380void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007381{
7382 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007383 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007384 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007385
Johan Hedberge1e930f2014-09-08 17:09:49 -07007386 bacpy(&ev.addr.bdaddr, &conn->dst);
7387 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7388 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007389
Johan Hedberge1e930f2014-09-08 17:09:49 -07007390 cmd = find_pairing(conn);
7391
7392 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7393 cmd ? cmd->sk : NULL);
7394
Johan Hedberga511b352014-12-11 21:45:45 +02007395 if (cmd) {
7396 cmd->cmd_complete(cmd, status);
7397 mgmt_pending_remove(cmd);
7398 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007399}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007400
Marcel Holtmann464996a2013-10-15 14:26:24 -07007401void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007402{
7403 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007404 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007405
7406 if (status) {
7407 u8 mgmt_err = mgmt_status(status);
7408 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007409 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007410 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007411 }
7412
Marcel Holtmann464996a2013-10-15 14:26:24 -07007413 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007414 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007415 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007416 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007417
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007418 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007419 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007420
Johan Hedberg47990ea2012-02-22 11:58:37 +02007421 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007422 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007423
7424 if (match.sk)
7425 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007426}
7427
Johan Hedberg890ea892013-03-15 17:06:52 -05007428static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007429{
Johan Hedberg890ea892013-03-15 17:06:52 -05007430 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007431 struct hci_cp_write_eir cp;
7432
Johan Hedberg976eb202012-10-24 21:12:01 +03007433 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007434 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007435
Johan Hedbergc80da272012-02-22 15:38:48 +02007436 memset(hdev->eir, 0, sizeof(hdev->eir));
7437
Johan Hedbergcacaf522012-02-21 00:52:42 +02007438 memset(&cp, 0, sizeof(cp));
7439
Johan Hedberg890ea892013-03-15 17:06:52 -05007440 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007441}
7442
Marcel Holtmann3e248562013-10-15 14:26:25 -07007443void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007444{
7445 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007446 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007447 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007448
7449 if (status) {
7450 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007451
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007452 if (enable && hci_dev_test_and_clear_flag(hdev,
7453 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007454 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007455 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007456 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007457
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007458 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7459 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007460 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007461 }
7462
7463 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007464 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007465 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007466 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007467 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007468 changed = hci_dev_test_and_clear_flag(hdev,
7469 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007470 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007471 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007472 }
7473
7474 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7475
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007476 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007477 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007478
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007479 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007480 sock_put(match.sk);
7481
Johan Hedberg890ea892013-03-15 17:06:52 -05007482 hci_req_init(&req, hdev);
7483
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007484 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7485 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007486 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7487 sizeof(enable), &enable);
Johan Hedberg890ea892013-03-15 17:06:52 -05007488 update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007489 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007490 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007491 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007492
7493 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007494}
7495
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007496static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007497{
7498 struct cmd_lookup *match = data;
7499
Johan Hedberg90e70452012-02-23 23:09:40 +02007500 if (match->sk == NULL) {
7501 match->sk = cmd->sk;
7502 sock_hold(match->sk);
7503 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007504}
7505
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007506void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7507 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007508{
Johan Hedberg90e70452012-02-23 23:09:40 +02007509 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007510
Johan Hedberg92da6092013-03-15 17:06:55 -05007511 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7512 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7513 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007514
7515 if (!status)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007516 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7517 dev_class, 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02007518
7519 if (match.sk)
7520 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007521}
7522
Marcel Holtmann7667da32013-10-15 14:26:27 -07007523void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007524{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007525 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007526 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007527
Johan Hedberg13928972013-03-15 17:07:00 -05007528 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007529 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007530
7531 memset(&ev, 0, sizeof(ev));
7532 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007533 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007534
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007535 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007536 if (!cmd) {
7537 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007538
Johan Hedberg13928972013-03-15 17:07:00 -05007539 /* If this is a HCI command related to powering on the
7540 * HCI dev don't send any mgmt signals.
7541 */
7542 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007543 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007544 }
7545
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007546 mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7547 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007548}
Szymon Jancc35938b2011-03-22 13:12:21 +01007549
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007550void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
Johan Hedberg38da1702014-11-17 20:52:20 +02007551 u8 *rand192, u8 *hash256, u8 *rand256,
7552 u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01007553{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007554 struct mgmt_pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01007555
Johan Hedberg744cf192011-11-08 20:40:14 +02007556 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01007557
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007558 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01007559 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07007560 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01007561
7562 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02007563 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
7564 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01007565 } else {
Johan Hedberg66f096f2015-02-02 13:23:42 +02007566 struct mgmt_rp_read_local_oob_data rp;
7567 size_t rp_size = sizeof(rp);
7568
7569 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
7570 memcpy(rp.rand192, rand192, sizeof(rp.rand192));
7571
Johan Hedberg710f11c2014-05-26 11:21:22 +03007572 if (bredr_sc_enabled(hdev) && hash256 && rand256) {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007573 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
Johan Hedberg38da1702014-11-17 20:52:20 +02007574 memcpy(rp.rand256, rand256, sizeof(rp.rand256));
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007575 } else {
Johan Hedberg66f096f2015-02-02 13:23:42 +02007576 rp_size -= sizeof(rp.hash256) + sizeof(rp.rand256);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007577 }
Johan Hedberg66f096f2015-02-02 13:23:42 +02007578
Johan Hedberg2a1afb52015-03-06 21:08:54 +02007579 mgmt_cmd_complete(cmd->sk, hdev->id,
7580 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
7581 &rp, rp_size);
Szymon Jancc35938b2011-03-22 13:12:21 +01007582 }
7583
7584 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01007585}
Johan Hedberge17acd42011-03-30 23:57:16 +03007586
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007587static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7588{
7589 int i;
7590
7591 for (i = 0; i < uuid_count; i++) {
7592 if (!memcmp(uuid, uuids[i], 16))
7593 return true;
7594 }
7595
7596 return false;
7597}
7598
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007599static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7600{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007601 u16 parsed = 0;
7602
7603 while (parsed < eir_len) {
7604 u8 field_len = eir[0];
7605 u8 uuid[16];
7606 int i;
7607
7608 if (field_len == 0)
7609 break;
7610
7611 if (eir_len - parsed < field_len + 1)
7612 break;
7613
7614 switch (eir[1]) {
7615 case EIR_UUID16_ALL:
7616 case EIR_UUID16_SOME:
7617 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007618 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007619 uuid[13] = eir[i + 3];
7620 uuid[12] = eir[i + 2];
7621 if (has_uuid(uuid, uuid_count, uuids))
7622 return true;
7623 }
7624 break;
7625 case EIR_UUID32_ALL:
7626 case EIR_UUID32_SOME:
7627 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007628 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007629 uuid[15] = eir[i + 5];
7630 uuid[14] = eir[i + 4];
7631 uuid[13] = eir[i + 3];
7632 uuid[12] = eir[i + 2];
7633 if (has_uuid(uuid, uuid_count, uuids))
7634 return true;
7635 }
7636 break;
7637 case EIR_UUID128_ALL:
7638 case EIR_UUID128_SOME:
7639 for (i = 0; i + 17 <= field_len; i += 16) {
7640 memcpy(uuid, eir + i + 2, 16);
7641 if (has_uuid(uuid, uuid_count, uuids))
7642 return true;
7643 }
7644 break;
7645 }
7646
7647 parsed += field_len + 1;
7648 eir += field_len + 1;
7649 }
7650
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007651 return false;
7652}
7653
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007654static void restart_le_scan(struct hci_dev *hdev)
7655{
7656 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007657 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007658 return;
7659
7660 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7661 hdev->discovery.scan_start +
7662 hdev->discovery.scan_duration))
7663 return;
7664
7665 queue_delayed_work(hdev->workqueue, &hdev->le_scan_restart,
7666 DISCOV_LE_RESTART_DELAY);
7667}
7668
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007669static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7670 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7671{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007672 /* If a RSSI threshold has been specified, and
7673 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7674 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7675 * is set, let it through for further processing, as we might need to
7676 * restart the scan.
7677 *
7678 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7679 * the results are also dropped.
7680 */
7681 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7682 (rssi == HCI_RSSI_INVALID ||
7683 (rssi < hdev->discovery.rssi &&
7684 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7685 return false;
7686
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007687 if (hdev->discovery.uuid_count != 0) {
7688 /* If a list of UUIDs is provided in filter, results with no
7689 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007690 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007691 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7692 hdev->discovery.uuids) &&
7693 !eir_has_uuids(scan_rsp, scan_rsp_len,
7694 hdev->discovery.uuid_count,
7695 hdev->discovery.uuids))
7696 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007697 }
7698
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007699 /* If duplicate filtering does not report RSSI changes, then restart
7700 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007701 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007702 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7703 restart_le_scan(hdev);
7704
7705 /* Validate RSSI value against the RSSI threshold once more. */
7706 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7707 rssi < hdev->discovery.rssi)
7708 return false;
7709 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007710
7711 return true;
7712}
7713
Marcel Holtmann901801b2013-10-06 23:55:51 -07007714void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007715 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7716 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007717{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007718 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007719 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007720 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007721
Johan Hedberg75ce2082014-07-02 22:42:01 +03007722 /* Don't send events for a non-kernel initiated discovery. With
7723 * LE one exception is if we have pend_le_reports > 0 in which
7724 * case we're doing passive scanning and want these events.
7725 */
7726 if (!hci_discovery_active(hdev)) {
7727 if (link_type == ACL_LINK)
7728 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007729 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007730 return;
7731 }
Andre Guedes12602d02013-04-30 15:29:40 -03007732
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007733 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007734 /* We are using service discovery */
7735 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7736 scan_rsp_len))
7737 return;
7738 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007739
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007740 /* Make sure that the buffer is big enough. The 5 extra bytes
7741 * are for the potential CoD field.
7742 */
7743 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007744 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007745
Johan Hedberg1dc06092012-01-15 21:01:23 +02007746 memset(buf, 0, sizeof(buf));
7747
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007748 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7749 * RSSI value was reported as 0 when not available. This behavior
7750 * is kept when using device discovery. This is required for full
7751 * backwards compatibility with the API.
7752 *
7753 * However when using service discovery, the value 127 will be
7754 * returned when the RSSI is not available.
7755 */
Szymon Janc91200e92015-01-22 16:57:05 +01007756 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7757 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007758 rssi = 0;
7759
Johan Hedberg841c5642014-07-07 12:45:54 +03007760 bacpy(&ev->addr.bdaddr, bdaddr);
7761 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007762 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007763 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007764
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007765 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007766 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007767 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007768
Johan Hedberg1dc06092012-01-15 21:01:23 +02007769 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
7770 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007771 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007772
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007773 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007774 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007775 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007776
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007777 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7778 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007779
Marcel Holtmann901801b2013-10-06 23:55:51 -07007780 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007781}
Johan Hedberga88a9652011-03-30 13:18:12 +03007782
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007783void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7784 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007785{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007786 struct mgmt_ev_device_found *ev;
7787 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7788 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007789
Johan Hedbergb644ba32012-01-17 21:48:47 +02007790 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007791
Johan Hedbergb644ba32012-01-17 21:48:47 +02007792 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007793
Johan Hedbergb644ba32012-01-17 21:48:47 +02007794 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007795 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007796 ev->rssi = rssi;
7797
7798 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007799 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007800
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007801 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007802
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007803 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007804}
Johan Hedberg314b2382011-04-27 10:29:57 -04007805
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007806void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007807{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007808 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007809
Andre Guedes343fb142011-11-22 17:14:19 -03007810 BT_DBG("%s discovering %u", hdev->name, discovering);
7811
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007812 memset(&ev, 0, sizeof(ev));
7813 ev.type = hdev->discovery.type;
7814 ev.discovering = discovering;
7815
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007816 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007817}
Antti Julku5e762442011-08-25 16:48:02 +03007818
Marcel Holtmann1904a852015-01-11 13:50:44 -08007819static void adv_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Marcel Holtmann5976e602013-10-06 04:08:14 -07007820{
7821 BT_DBG("%s status %u", hdev->name, status);
Marcel Holtmann5976e602013-10-06 04:08:14 -07007822}
7823
7824void mgmt_reenable_advertising(struct hci_dev *hdev)
7825{
7826 struct hci_request req;
7827
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007828 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Marcel Holtmann5976e602013-10-06 04:08:14 -07007829 return;
7830
7831 hci_req_init(&req, hdev);
7832 enable_advertising(&req);
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03007833 hci_req_run(&req, adv_enable_complete);
Marcel Holtmann5976e602013-10-06 04:08:14 -07007834}
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007835
7836static struct hci_mgmt_chan chan = {
7837 .channel = HCI_CHANNEL_CONTROL,
7838 .handler_count = ARRAY_SIZE(mgmt_handlers),
7839 .handlers = mgmt_handlers,
7840};
7841
7842int mgmt_init(void)
7843{
7844 return hci_mgmt_chan_register(&chan);
7845}
7846
7847void mgmt_exit(void)
7848{
7849 hci_mgmt_chan_unregister(&chan);
7850}