blob: 3d7dbdde7008fdf9fa07ced1387d8cc3667e056b [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 Hedberg333ae952015-03-17 13:48:47 +0200885static struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel,
886 u16 opcode,
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200887 struct hci_dev *hdev)
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300888{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200889 struct mgmt_pending_cmd *cmd;
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300890
891 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberg333ae952015-03-17 13:48:47 +0200892 if (hci_sock_get_channel(cmd->sk) != channel)
893 continue;
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300894 if (cmd->opcode == opcode)
895 return cmd;
896 }
897
898 return NULL;
899}
900
Johan Hedberg333ae952015-03-17 13:48:47 +0200901static struct mgmt_pending_cmd *pending_find(u16 opcode, struct hci_dev *hdev)
902{
903 return mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
904}
905
906static struct mgmt_pending_cmd *mgmt_pending_find_data(unsigned short channel,
907 u16 opcode,
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200908 struct hci_dev *hdev,
909 const void *data)
Johan Hedberg95868422014-06-28 17:54:07 +0300910{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200911 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +0300912
913 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
914 if (cmd->user_data != data)
915 continue;
916 if (cmd->opcode == opcode)
917 return cmd;
918 }
919
920 return NULL;
921}
922
Johan Hedberg333ae952015-03-17 13:48:47 +0200923static struct mgmt_pending_cmd *pending_find_data(u16 opcode,
924 struct hci_dev *hdev,
925 const void *data)
926{
927 return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data);
928}
929
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700930static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
931{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700932 u8 ad_len = 0;
933 size_t name_len;
934
935 name_len = strlen(hdev->dev_name);
936 if (name_len > 0) {
937 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
938
939 if (name_len > max_len) {
940 name_len = max_len;
941 ptr[1] = EIR_NAME_SHORT;
942 } else
943 ptr[1] = EIR_NAME_COMPLETE;
944
945 ptr[0] = name_len + 1;
946
947 memcpy(ptr + 2, hdev->dev_name, name_len);
948
949 ad_len += (name_len + 2);
950 ptr += (name_len + 2);
951 }
952
953 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700954}
955
956static void update_scan_rsp_data(struct hci_request *req)
957{
958 struct hci_dev *hdev = req->hdev;
959 struct hci_cp_le_set_scan_rsp_data cp;
960 u8 len;
961
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700962 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700963 return;
964
965 memset(&cp, 0, sizeof(cp));
966
967 len = create_scan_rsp_data(hdev, cp.data);
968
Johan Hedbergeb438b52013-10-16 15:31:07 +0300969 if (hdev->scan_rsp_data_len == len &&
970 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700971 return;
972
Johan Hedbergeb438b52013-10-16 15:31:07 +0300973 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
974 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700975
976 cp.length = len;
977
978 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
979}
980
Johan Hedberg9a43e252013-10-20 19:00:07 +0300981static u8 get_adv_discov_flags(struct hci_dev *hdev)
982{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200983 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300984
985 /* If there's a pending mgmt command the flags will not yet have
986 * their final values, so check for this first.
987 */
Johan Hedberg333ae952015-03-17 13:48:47 +0200988 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg9a43e252013-10-20 19:00:07 +0300989 if (cmd) {
990 struct mgmt_mode *cp = cmd->param;
991 if (cp->val == 0x01)
992 return LE_AD_GENERAL;
993 else if (cp->val == 0x02)
994 return LE_AD_LIMITED;
995 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700996 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300997 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700998 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300999 return LE_AD_GENERAL;
1000 }
1001
1002 return 0;
1003}
1004
Marcel Holtmann46cad2e2013-10-16 00:16:46 -07001005static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001006{
1007 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001008
Johan Hedberg9a43e252013-10-20 19:00:07 +03001009 flags |= get_adv_discov_flags(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001010
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001011 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001012 flags |= LE_AD_NO_BREDR;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001013
1014 if (flags) {
1015 BT_DBG("adv flags 0x%02x", flags);
1016
1017 ptr[0] = 2;
1018 ptr[1] = EIR_FLAGS;
1019 ptr[2] = flags;
1020
1021 ad_len += 3;
1022 ptr += 3;
1023 }
1024
1025 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
1026 ptr[0] = 2;
1027 ptr[1] = EIR_TX_POWER;
1028 ptr[2] = (u8) hdev->adv_tx_power;
1029
1030 ad_len += 3;
1031 ptr += 3;
1032 }
1033
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001034 return ad_len;
1035}
1036
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001037static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001038{
1039 struct hci_dev *hdev = req->hdev;
1040 struct hci_cp_le_set_adv_data cp;
1041 u8 len;
1042
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001043 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001044 return;
1045
1046 memset(&cp, 0, sizeof(cp));
1047
Marcel Holtmann46cad2e2013-10-16 00:16:46 -07001048 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001049
1050 if (hdev->adv_data_len == len &&
1051 memcmp(cp.data, hdev->adv_data, len) == 0)
1052 return;
1053
1054 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
1055 hdev->adv_data_len = len;
1056
1057 cp.length = len;
1058
1059 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
1060}
1061
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001062int mgmt_update_adv_data(struct hci_dev *hdev)
1063{
1064 struct hci_request req;
1065
1066 hci_req_init(&req, hdev);
1067 update_adv_data(&req);
1068
1069 return hci_req_run(&req, NULL);
1070}
1071
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001072static void create_eir(struct hci_dev *hdev, u8 *data)
1073{
1074 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001075 size_t name_len;
1076
1077 name_len = strlen(hdev->dev_name);
1078
1079 if (name_len > 0) {
1080 /* EIR Data type */
1081 if (name_len > 48) {
1082 name_len = 48;
1083 ptr[1] = EIR_NAME_SHORT;
1084 } else
1085 ptr[1] = EIR_NAME_COMPLETE;
1086
1087 /* EIR Data length */
1088 ptr[0] = name_len + 1;
1089
1090 memcpy(ptr + 2, hdev->dev_name, name_len);
1091
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001092 ptr += (name_len + 2);
1093 }
1094
Johan Hedbergbbaf4442012-11-08 01:22:59 +01001095 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -07001096 ptr[0] = 2;
1097 ptr[1] = EIR_TX_POWER;
1098 ptr[2] = (u8) hdev->inq_tx_power;
1099
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -07001100 ptr += 3;
1101 }
1102
Marcel Holtmann2b9be132012-03-11 19:32:12 -07001103 if (hdev->devid_source > 0) {
1104 ptr[0] = 9;
1105 ptr[1] = EIR_DEVICE_ID;
1106
1107 put_unaligned_le16(hdev->devid_source, ptr + 2);
1108 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
1109 put_unaligned_le16(hdev->devid_product, ptr + 6);
1110 put_unaligned_le16(hdev->devid_version, ptr + 8);
1111
Marcel Holtmann2b9be132012-03-11 19:32:12 -07001112 ptr += 10;
1113 }
1114
Johan Hedberg213202e2013-01-27 00:31:33 +02001115 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +02001116 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +02001117 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001118}
1119
Johan Hedberg890ea892013-03-15 17:06:52 -05001120static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001121{
Johan Hedberg890ea892013-03-15 17:06:52 -05001122 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001123 struct hci_cp_write_eir cp;
1124
Johan Hedberg504c8dc2012-02-23 13:30:41 +02001125 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001126 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +02001127
Johan Hedberg976eb202012-10-24 21:12:01 +03001128 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001129 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001130
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001131 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg890ea892013-03-15 17:06:52 -05001132 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001133
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001134 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -05001135 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001136
1137 memset(&cp, 0, sizeof(cp));
1138
1139 create_eir(hdev, cp.data);
1140
1141 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -05001142 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001143
1144 memcpy(hdev->eir, cp.data, sizeof(cp.data));
1145
Johan Hedberg890ea892013-03-15 17:06:52 -05001146 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001147}
1148
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001149static u8 get_service_classes(struct hci_dev *hdev)
1150{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -03001151 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001152 u8 val = 0;
1153
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -03001154 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001155 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001156
1157 return val;
1158}
1159
Johan Hedberg890ea892013-03-15 17:06:52 -05001160static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001161{
Johan Hedberg890ea892013-03-15 17:06:52 -05001162 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001163 u8 cod[3];
1164
1165 BT_DBG("%s", hdev->name);
1166
Johan Hedberg504c8dc2012-02-23 13:30:41 +02001167 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001168 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +02001169
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001170 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedbergf87ea1d2013-10-19 23:38:17 +03001171 return;
1172
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001173 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -05001174 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001175
1176 cod[0] = hdev->minor_class;
1177 cod[1] = hdev->major_class;
1178 cod[2] = get_service_classes(hdev);
1179
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001180 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Marcel Holtmann6acd7db2013-10-15 06:33:53 -07001181 cod[1] |= 0x20;
1182
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001183 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -05001184 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001185
Johan Hedberg890ea892013-03-15 17:06:52 -05001186 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001187}
1188
Johan Hedberga4858cb2014-02-25 19:56:31 +02001189static bool get_connectable(struct hci_dev *hdev)
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001190{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001191 struct mgmt_pending_cmd *cmd;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001192
1193 /* If there's a pending mgmt command the flag will not yet have
1194 * it's final value, so check for this first.
1195 */
Johan Hedberg333ae952015-03-17 13:48:47 +02001196 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001197 if (cmd) {
1198 struct mgmt_mode *cp = cmd->param;
Johan Hedberga4858cb2014-02-25 19:56:31 +02001199 return cp->val;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001200 }
1201
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001202 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001203}
1204
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001205static void disable_advertising(struct hci_request *req)
1206{
1207 u8 enable = 0x00;
1208
1209 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1210}
1211
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001212static void enable_advertising(struct hci_request *req)
1213{
1214 struct hci_dev *hdev = req->hdev;
1215 struct hci_cp_le_set_adv_param cp;
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001216 u8 own_addr_type, enable = 0x01;
Johan Hedberga4858cb2014-02-25 19:56:31 +02001217 bool connectable;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001218
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001219 if (hci_conn_num(hdev, LE_LINK) > 0)
1220 return;
1221
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001222 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001223 disable_advertising(req);
1224
Johan Hedberg5ce194c2014-07-08 15:07:49 +03001225 /* Clear the HCI_LE_ADV bit temporarily so that the
Johan Hedberg8d972502014-02-28 12:54:14 +02001226 * hci_update_random_address knows that it's safe to go ahead
1227 * and write a new random address. The flag will be set back on
1228 * as soon as the SET_ADV_ENABLE HCI command completes.
1229 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001230 hci_dev_clear_flag(hdev, HCI_LE_ADV);
Johan Hedberg8d972502014-02-28 12:54:14 +02001231
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001232 if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07001233 connectable = true;
1234 else
1235 connectable = get_connectable(hdev);
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001236
Johan Hedberga4858cb2014-02-25 19:56:31 +02001237 /* Set require_privacy to true only when non-connectable
1238 * advertising is used. In that case it is fine to use a
1239 * non-resolvable private address.
1240 */
1241 if (hci_update_random_address(req, !connectable, &own_addr_type) < 0)
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001242 return;
1243
Marcel Holtmann41c90c12014-02-23 20:25:55 -08001244 memset(&cp, 0, sizeof(cp));
Georg Lukas628531c2014-07-26 13:59:57 +02001245 cp.min_interval = cpu_to_le16(hdev->le_adv_min_interval);
1246 cp.max_interval = cpu_to_le16(hdev->le_adv_max_interval);
Johan Hedberga4858cb2014-02-25 19:56:31 +02001247 cp.type = connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001248 cp.own_address_type = own_addr_type;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001249 cp.channel_map = hdev->le_adv_channel_map;
1250
1251 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1252
1253 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1254}
1255
Johan Hedberg7d785252011-12-15 00:47:39 +02001256static void service_cache_off(struct work_struct *work)
1257{
1258 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001259 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -05001260 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +02001261
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001262 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +02001263 return;
1264
Johan Hedberg890ea892013-03-15 17:06:52 -05001265 hci_req_init(&req, hdev);
1266
Johan Hedberg7d785252011-12-15 00:47:39 +02001267 hci_dev_lock(hdev);
1268
Johan Hedberg890ea892013-03-15 17:06:52 -05001269 update_eir(&req);
1270 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001271
1272 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001273
1274 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +02001275}
1276
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001277static void rpa_expired(struct work_struct *work)
1278{
1279 struct hci_dev *hdev = container_of(work, struct hci_dev,
1280 rpa_expired.work);
1281 struct hci_request req;
1282
1283 BT_DBG("");
1284
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001285 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001286
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001287 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001288 return;
1289
1290 /* The generation of a new RPA and programming it into the
1291 * controller happens in the enable_advertising() function.
1292 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001293 hci_req_init(&req, hdev);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001294 enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001295 hci_req_run(&req, NULL);
1296}
1297
Johan Hedberg6a919082012-02-28 06:17:26 +02001298static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +02001299{
Marcel Holtmann238be782015-03-13 02:11:06 -07001300 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +02001301 return;
1302
Johan Hedberg4f87da82012-03-02 19:55:56 +02001303 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001304 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +02001305
Johan Hedberg4f87da82012-03-02 19:55:56 +02001306 /* Non-mgmt controlled devices get this bit set
1307 * implicitly so that pairing works for them, however
1308 * for mgmt we require user-space to explicitly enable
1309 * it
1310 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001311 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +02001312}
1313
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001314static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001315 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001316{
1317 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001318
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001319 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001320
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001321 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001322
Johan Hedberg03811012010-12-08 00:21:06 +02001323 memset(&rp, 0, sizeof(rp));
1324
Johan Hedberg03811012010-12-08 00:21:06 +02001325 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001326
1327 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001328 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001329
1330 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1331 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1332
1333 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +02001334
1335 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001336 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +02001337
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001338 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001339
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001340 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1341 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +02001342}
1343
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001344static void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
Johan Hedberg03811012010-12-08 00:21:06 +02001345{
1346 sock_put(cmd->sk);
1347 kfree(cmd->param);
1348 kfree(cmd);
1349}
1350
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001351static struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
1352 struct hci_dev *hdev,
1353 void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001354{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001355 struct mgmt_pending_cmd *cmd;
Johan Hedberg03811012010-12-08 00:21:06 +02001356
Johan Hedbergfca20012014-06-28 17:54:05 +03001357 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001358 if (!cmd)
1359 return NULL;
1360
1361 cmd->opcode = opcode;
1362 cmd->index = hdev->id;
1363
Johan Hedberg323b0b82014-12-05 13:36:01 +02001364 cmd->param = kmemdup(data, len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001365 if (!cmd->param) {
1366 kfree(cmd);
1367 return NULL;
1368 }
1369
Johan Hedberg323b0b82014-12-05 13:36:01 +02001370 cmd->param_len = len;
Johan Hedberg03811012010-12-08 00:21:06 +02001371
1372 cmd->sk = sk;
1373 sock_hold(sk);
1374
1375 list_add(&cmd->list, &hdev->mgmt_pending);
1376
1377 return cmd;
1378}
1379
1380static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001381 void (*cb)(struct mgmt_pending_cmd *cmd,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001382 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001383 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02001384{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001385 struct mgmt_pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +02001386
Andre Guedesa3d09352013-02-01 11:21:30 -03001387 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +02001388 if (opcode > 0 && cmd->opcode != opcode)
1389 continue;
1390
1391 cb(cmd, data);
1392 }
1393}
1394
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001395static void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
Johan Hedberg03811012010-12-08 00:21:06 +02001396{
1397 list_del(&cmd->list);
1398 mgmt_pending_free(cmd);
1399}
1400
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001401static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001402{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001403 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001404
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001405 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1406 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001407}
1408
Marcel Holtmann1904a852015-01-11 13:50:44 -08001409static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001410{
1411 BT_DBG("%s status 0x%02x", hdev->name, status);
1412
Johan Hedberga3172b72014-02-28 09:33:44 +02001413 if (hci_conn_count(hdev) == 0) {
1414 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001415 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001416 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001417}
1418
Johan Hedberg23a48092014-07-08 16:05:06 +03001419static bool hci_stop_discovery(struct hci_request *req)
Johan Hedberg21a60d32014-06-10 14:05:58 +03001420{
1421 struct hci_dev *hdev = req->hdev;
1422 struct hci_cp_remote_name_req_cancel cp;
1423 struct inquiry_entry *e;
1424
1425 switch (hdev->discovery.state) {
1426 case DISCOVERY_FINDING:
Jakub Pawlowski07d23342015-03-17 09:04:14 -07001427 if (test_bit(HCI_INQUIRY, &hdev->flags))
Johan Hedberg21a60d32014-06-10 14:05:58 +03001428 hci_req_add(req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
Jakub Pawlowski07d23342015-03-17 09:04:14 -07001429
1430 if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
Johan Hedberg21a60d32014-06-10 14:05:58 +03001431 cancel_delayed_work(&hdev->le_scan_disable);
1432 hci_req_add_le_scan_disable(req);
1433 }
1434
Johan Hedberg23a48092014-07-08 16:05:06 +03001435 return true;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001436
1437 case DISCOVERY_RESOLVING:
1438 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
1439 NAME_PENDING);
1440 if (!e)
Johan Hedberg23a48092014-07-08 16:05:06 +03001441 break;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001442
1443 bacpy(&cp.bdaddr, &e->data.bdaddr);
1444 hci_req_add(req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
1445 &cp);
1446
Johan Hedberg23a48092014-07-08 16:05:06 +03001447 return true;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001448
1449 default:
1450 /* Passive scanning */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001451 if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
Johan Hedberg21a60d32014-06-10 14:05:58 +03001452 hci_req_add_le_scan_disable(req);
Johan Hedberg23a48092014-07-08 16:05:06 +03001453 return true;
1454 }
1455
Johan Hedberg21a60d32014-06-10 14:05:58 +03001456 break;
1457 }
Johan Hedberg23a48092014-07-08 16:05:06 +03001458
1459 return false;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001460}
1461
Johan Hedberg8b064a32014-02-24 14:52:22 +02001462static int clean_up_hci_state(struct hci_dev *hdev)
1463{
1464 struct hci_request req;
1465 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001466 bool discov_stopped;
1467 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001468
1469 hci_req_init(&req, hdev);
1470
1471 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1472 test_bit(HCI_PSCAN, &hdev->flags)) {
1473 u8 scan = 0x00;
1474 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1475 }
1476
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001477 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedberg8b064a32014-02-24 14:52:22 +02001478 disable_advertising(&req);
1479
Johan Hedberg23a48092014-07-08 16:05:06 +03001480 discov_stopped = hci_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001481
1482 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
1483 struct hci_cp_disconnect dc;
Johan Hedbergc9910d02014-02-27 14:35:12 +02001484 struct hci_cp_reject_conn_req rej;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001485
Johan Hedbergc9910d02014-02-27 14:35:12 +02001486 switch (conn->state) {
1487 case BT_CONNECTED:
1488 case BT_CONFIG:
1489 dc.handle = cpu_to_le16(conn->handle);
1490 dc.reason = 0x15; /* Terminated due to Power Off */
1491 hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1492 break;
1493 case BT_CONNECT:
1494 if (conn->type == LE_LINK)
1495 hci_req_add(&req, HCI_OP_LE_CREATE_CONN_CANCEL,
1496 0, NULL);
1497 else if (conn->type == ACL_LINK)
1498 hci_req_add(&req, HCI_OP_CREATE_CONN_CANCEL,
1499 6, &conn->dst);
1500 break;
1501 case BT_CONNECT2:
1502 bacpy(&rej.bdaddr, &conn->dst);
1503 rej.reason = 0x15; /* Terminated due to Power Off */
1504 if (conn->type == ACL_LINK)
1505 hci_req_add(&req, HCI_OP_REJECT_CONN_REQ,
1506 sizeof(rej), &rej);
1507 else if (conn->type == SCO_LINK)
1508 hci_req_add(&req, HCI_OP_REJECT_SYNC_CONN_REQ,
1509 sizeof(rej), &rej);
1510 break;
1511 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001512 }
1513
Johan Hedberg23a48092014-07-08 16:05:06 +03001514 err = hci_req_run(&req, clean_up_hci_complete);
1515 if (!err && discov_stopped)
1516 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1517
1518 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001519}
1520
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001521static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001522 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001523{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001524 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001525 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001526 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001527
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001528 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001529
Johan Hedberga7e80f22013-01-09 16:05:19 +02001530 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001531 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1532 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001533
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001534 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001535
Johan Hedberg333ae952015-03-17 13:48:47 +02001536 if (pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001537 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1538 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001539 goto failed;
1540 }
1541
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001542 if (hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001543 cancel_delayed_work(&hdev->power_off);
1544
1545 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +02001546 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
1547 data, len);
1548 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001549 goto failed;
1550 }
1551 }
1552
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001553 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001554 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001555 goto failed;
1556 }
1557
Johan Hedberg03811012010-12-08 00:21:06 +02001558 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1559 if (!cmd) {
1560 err = -ENOMEM;
1561 goto failed;
1562 }
1563
Johan Hedberg8b064a32014-02-24 14:52:22 +02001564 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001565 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001566 err = 0;
1567 } else {
1568 /* Disconnect connections, stop scans, etc */
1569 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001570 if (!err)
1571 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1572 HCI_POWER_OFF_TIMEOUT);
Johan Hedberg03811012010-12-08 00:21:06 +02001573
Johan Hedberg8b064a32014-02-24 14:52:22 +02001574 /* ENODATA means there were no HCI commands queued */
1575 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001576 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001577 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1578 err = 0;
1579 }
1580 }
Johan Hedberg03811012010-12-08 00:21:06 +02001581
1582failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001583 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001584 return err;
1585}
1586
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001587static int new_settings(struct hci_dev *hdev, struct sock *skip)
1588{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001589 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001590
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001591 return mgmt_generic_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1592 sizeof(ev), skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001593}
1594
Johan Hedberg91a668b2014-07-09 13:28:26 +03001595int mgmt_new_settings(struct hci_dev *hdev)
1596{
1597 return new_settings(hdev, NULL);
1598}
1599
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001600struct cmd_lookup {
1601 struct sock *sk;
1602 struct hci_dev *hdev;
1603 u8 mgmt_status;
1604};
1605
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001606static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001607{
1608 struct cmd_lookup *match = data;
1609
1610 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1611
1612 list_del(&cmd->list);
1613
1614 if (match->sk == NULL) {
1615 match->sk = cmd->sk;
1616 sock_hold(match->sk);
1617 }
1618
1619 mgmt_pending_free(cmd);
1620}
1621
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001622static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001623{
1624 u8 *status = data;
1625
Johan Hedberga69e8372015-03-06 21:08:53 +02001626 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001627 mgmt_pending_remove(cmd);
1628}
1629
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001630static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001631{
1632 if (cmd->cmd_complete) {
1633 u8 *status = data;
1634
1635 cmd->cmd_complete(cmd, *status);
1636 mgmt_pending_remove(cmd);
1637
1638 return;
1639 }
1640
1641 cmd_status_rsp(cmd, data);
1642}
1643
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001644static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001645{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001646 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1647 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001648}
1649
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001650static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001651{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001652 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1653 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001654}
1655
Johan Hedberge6fe7982013-10-02 15:45:22 +03001656static u8 mgmt_bredr_support(struct hci_dev *hdev)
1657{
1658 if (!lmp_bredr_capable(hdev))
1659 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001660 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001661 return MGMT_STATUS_REJECTED;
1662 else
1663 return MGMT_STATUS_SUCCESS;
1664}
1665
1666static u8 mgmt_le_support(struct hci_dev *hdev)
1667{
1668 if (!lmp_le_capable(hdev))
1669 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001670 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001671 return MGMT_STATUS_REJECTED;
1672 else
1673 return MGMT_STATUS_SUCCESS;
1674}
1675
Marcel Holtmann1904a852015-01-11 13:50:44 -08001676static void set_discoverable_complete(struct hci_dev *hdev, u8 status,
1677 u16 opcode)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001678{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001679 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001680 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001681 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001682 bool changed;
1683
1684 BT_DBG("status 0x%02x", status);
1685
1686 hci_dev_lock(hdev);
1687
Johan Hedberg333ae952015-03-17 13:48:47 +02001688 cmd = pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001689 if (!cmd)
1690 goto unlock;
1691
1692 if (status) {
1693 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001694 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001695 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001696 goto remove_cmd;
1697 }
1698
1699 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001700 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001701 changed = !hci_dev_test_and_set_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001702
1703 if (hdev->discov_timeout > 0) {
1704 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1705 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1706 to);
1707 }
1708 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001709 changed = hci_dev_test_and_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001710 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001711
1712 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1713
1714 if (changed)
1715 new_settings(hdev, cmd->sk);
1716
Marcel Holtmann970ba522013-10-15 06:33:57 -07001717 /* When the discoverable mode gets changed, make sure
1718 * that class of device has the limited discoverable
Johan Hedberg432df052014-08-01 11:13:31 +03001719 * bit correctly set. Also update page scan based on whitelist
1720 * entries.
Marcel Holtmann970ba522013-10-15 06:33:57 -07001721 */
1722 hci_req_init(&req, hdev);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001723 __hci_update_page_scan(&req);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001724 update_class(&req);
1725 hci_req_run(&req, NULL);
1726
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001727remove_cmd:
1728 mgmt_pending_remove(cmd);
1729
1730unlock:
1731 hci_dev_unlock(hdev);
1732}
1733
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001734static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001735 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001736{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001737 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001738 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001739 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001740 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001741 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001742 int err;
Johan Hedberge41d8b42010-12-13 21:07:03 +02001743
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001744 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001745
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001746 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1747 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001748 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1749 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001750
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001751 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001752 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1753 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001754
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001755 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001756
1757 /* Disabling discoverable requires that no timeout is set,
1758 * and enabling limited discoverable requires a timeout.
1759 */
1760 if ((cp->val == 0x00 && timeout > 0) ||
1761 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001762 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1763 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001764
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001765 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001766
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001767 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001768 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1769 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001770 goto failed;
1771 }
1772
Johan Hedberg333ae952015-03-17 13:48:47 +02001773 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
1774 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001775 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1776 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001777 goto failed;
1778 }
1779
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001780 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001781 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1782 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001783 goto failed;
1784 }
1785
1786 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001787 bool changed = false;
1788
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001789 /* Setting limited discoverable when powered off is
1790 * not a valid operation since it requires a timeout
1791 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1792 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001793 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001794 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001795 changed = true;
1796 }
1797
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001798 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001799 if (err < 0)
1800 goto failed;
1801
1802 if (changed)
1803 err = new_settings(hdev, sk);
1804
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001805 goto failed;
1806 }
1807
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001808 /* If the current mode is the same, then just update the timeout
1809 * value with the new value. And if only the timeout gets updated,
1810 * then no need for any HCI transactions.
1811 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001812 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1813 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1814 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001815 cancel_delayed_work(&hdev->discov_off);
1816 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001817
Marcel Holtmann36261542013-10-15 08:28:51 -07001818 if (cp->val && hdev->discov_timeout > 0) {
1819 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001820 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001821 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001822 }
1823
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001824 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001825 goto failed;
1826 }
1827
1828 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1829 if (!cmd) {
1830 err = -ENOMEM;
1831 goto failed;
1832 }
1833
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001834 /* Cancel any potential discoverable timeout that might be
1835 * still active and store new timeout value. The arming of
1836 * the timeout happens in the complete handler.
1837 */
1838 cancel_delayed_work(&hdev->discov_off);
1839 hdev->discov_timeout = timeout;
1840
Johan Hedbergb456f872013-10-19 23:38:22 +03001841 /* Limited discoverable mode */
1842 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001843 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001844 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001845 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001846
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001847 hci_req_init(&req, hdev);
1848
Johan Hedberg9a43e252013-10-20 19:00:07 +03001849 /* The procedure for LE-only controllers is much simpler - just
1850 * update the advertising data.
1851 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001852 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg9a43e252013-10-20 19:00:07 +03001853 goto update_ad;
1854
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001855 scan = SCAN_PAGE;
1856
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001857 if (cp->val) {
1858 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001859
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001860 if (cp->val == 0x02) {
1861 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001862 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001863 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1864 hci_cp.iac_lap[1] = 0x8b;
1865 hci_cp.iac_lap[2] = 0x9e;
1866 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1867 hci_cp.iac_lap[4] = 0x8b;
1868 hci_cp.iac_lap[5] = 0x9e;
1869 } else {
1870 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001871 hci_cp.num_iac = 1;
1872 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1873 hci_cp.iac_lap[1] = 0x8b;
1874 hci_cp.iac_lap[2] = 0x9e;
1875 }
1876
1877 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1878 (hci_cp.num_iac * 3) + 1, &hci_cp);
1879
1880 scan |= SCAN_INQUIRY;
1881 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001882 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001883 }
1884
1885 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001886
Johan Hedberg9a43e252013-10-20 19:00:07 +03001887update_ad:
1888 update_adv_data(&req);
1889
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001890 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001891 if (err < 0)
1892 mgmt_pending_remove(cmd);
1893
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001894failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001895 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001896 return err;
1897}
1898
Johan Hedberg406d7802013-03-15 17:07:09 -05001899static void write_fast_connectable(struct hci_request *req, bool enable)
1900{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001901 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001902 struct hci_cp_write_page_scan_activity acp;
1903 u8 type;
1904
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001905 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg547003b2013-10-21 16:51:53 +03001906 return;
1907
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001908 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1909 return;
1910
Johan Hedberg406d7802013-03-15 17:07:09 -05001911 if (enable) {
1912 type = PAGE_SCAN_TYPE_INTERLACED;
1913
1914 /* 160 msec page scan interval */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001915 acp.interval = cpu_to_le16(0x0100);
Johan Hedberg406d7802013-03-15 17:07:09 -05001916 } else {
1917 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1918
1919 /* default 1.28 sec page scan */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001920 acp.interval = cpu_to_le16(0x0800);
Johan Hedberg406d7802013-03-15 17:07:09 -05001921 }
1922
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001923 acp.window = cpu_to_le16(0x0012);
Johan Hedberg406d7802013-03-15 17:07:09 -05001924
Johan Hedbergbd98b992013-03-15 17:07:13 -05001925 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1926 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1927 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1928 sizeof(acp), &acp);
1929
1930 if (hdev->page_scan_type != type)
1931 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001932}
1933
Marcel Holtmann1904a852015-01-11 13:50:44 -08001934static void set_connectable_complete(struct hci_dev *hdev, u8 status,
1935 u16 opcode)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001936{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001937 struct mgmt_pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001938 struct mgmt_mode *cp;
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001939 bool conn_changed, discov_changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001940
1941 BT_DBG("status 0x%02x", status);
1942
1943 hci_dev_lock(hdev);
1944
Johan Hedberg333ae952015-03-17 13:48:47 +02001945 cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg2b76f452013-03-15 17:07:04 -05001946 if (!cmd)
1947 goto unlock;
1948
Johan Hedberg37438c12013-10-14 16:20:05 +03001949 if (status) {
1950 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001951 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001952 goto remove_cmd;
1953 }
1954
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001955 cp = cmd->param;
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001956 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001957 conn_changed = !hci_dev_test_and_set_flag(hdev,
1958 HCI_CONNECTABLE);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001959 discov_changed = false;
1960 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001961 conn_changed = hci_dev_test_and_clear_flag(hdev,
1962 HCI_CONNECTABLE);
1963 discov_changed = hci_dev_test_and_clear_flag(hdev,
1964 HCI_DISCOVERABLE);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001965 }
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001966
Johan Hedberg2b76f452013-03-15 17:07:04 -05001967 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1968
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001969 if (conn_changed || discov_changed) {
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001970 new_settings(hdev, cmd->sk);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001971 hci_update_page_scan(hdev);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001972 if (discov_changed)
1973 mgmt_update_adv_data(hdev);
Johan Hedberg2b7be332014-07-07 14:40:22 +03001974 hci_update_background_scan(hdev);
1975 }
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001976
Johan Hedberg37438c12013-10-14 16:20:05 +03001977remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001978 mgmt_pending_remove(cmd);
1979
1980unlock:
1981 hci_dev_unlock(hdev);
1982}
1983
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001984static int set_connectable_update_settings(struct hci_dev *hdev,
1985 struct sock *sk, u8 val)
1986{
1987 bool changed = false;
1988 int err;
1989
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001990 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001991 changed = true;
1992
1993 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001994 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001995 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001996 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1997 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001998 }
1999
2000 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
2001 if (err < 0)
2002 return err;
2003
Johan Hedberg562064e2014-07-08 16:35:34 +03002004 if (changed) {
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02002005 hci_update_page_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03002006 hci_update_background_scan(hdev);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03002007 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03002008 }
Johan Hedberge8ba3a12013-10-19 23:38:18 +03002009
2010 return 0;
2011}
2012
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002013static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002014 u16 len)
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002015{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002016 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002017 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05002018 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03002019 u8 scan;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002020 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002021
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002022 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002023
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002024 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
2025 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02002026 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
2027 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03002028
Johan Hedberga7e80f22013-01-09 16:05:19 +02002029 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002030 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
2031 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002032
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002033 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002034
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002035 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03002036 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002037 goto failed;
2038 }
2039
Johan Hedberg333ae952015-03-17 13:48:47 +02002040 if (pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
2041 pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002042 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
2043 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002044 goto failed;
2045 }
2046
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002047 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
2048 if (!cmd) {
2049 err = -ENOMEM;
2050 goto failed;
2051 }
2052
Johan Hedberg2b76f452013-03-15 17:07:04 -05002053 hci_req_init(&req, hdev);
2054
Johan Hedberg9a43e252013-10-20 19:00:07 +03002055 /* If BR/EDR is not enabled and we disable advertising as a
2056 * by-product of disabling connectable, we need to update the
2057 * advertising flags.
2058 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002059 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg9a43e252013-10-20 19:00:07 +03002060 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002061 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
2062 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg9a43e252013-10-20 19:00:07 +03002063 }
2064 update_adv_data(&req);
2065 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03002066 if (cp->val) {
2067 scan = SCAN_PAGE;
2068 } else {
Johan Hedberg3bd27242014-07-28 20:53:58 +03002069 /* If we don't have any whitelist entries just
2070 * disable all scanning. If there are entries
2071 * and we had both page and inquiry scanning
2072 * enabled then fall back to only page scanning.
2073 * Otherwise no changes are needed.
2074 */
2075 if (list_empty(&hdev->whitelist))
2076 scan = SCAN_DISABLED;
2077 else if (test_bit(HCI_ISCAN, &hdev->flags))
2078 scan = SCAN_PAGE;
2079 else
2080 goto no_scan_update;
Johan Hedberg9b742462013-10-14 16:20:03 +03002081
2082 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07002083 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03002084 cancel_delayed_work(&hdev->discov_off);
2085 }
2086
2087 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
2088 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05002089
Johan Hedberg3bd27242014-07-28 20:53:58 +03002090no_scan_update:
Johan Hedberge8b12022014-07-10 10:51:27 +03002091 /* Update the advertising parameters if necessary */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002092 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedberg1987fdc2013-10-14 21:15:24 +03002093 enable_advertising(&req);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03002094
Johan Hedberg2b76f452013-03-15 17:07:04 -05002095 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03002096 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002097 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03002098 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03002099 err = set_connectable_update_settings(hdev, sk,
2100 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03002101 goto failed;
2102 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002103
2104failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002105 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002106 return err;
2107}
2108
Johan Hedbergb2939472014-07-30 09:22:23 +03002109static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002110 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002111{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002112 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07002113 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002114 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002115
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002116 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002117
Johan Hedberga7e80f22013-01-09 16:05:19 +02002118 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002119 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
2120 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002121
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002122 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002123
2124 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07002125 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002126 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002127 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002128
Johan Hedbergb2939472014-07-30 09:22:23 +03002129 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002130 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07002131 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002132
Marcel Holtmann55594352013-10-06 16:11:57 -07002133 if (changed)
2134 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002135
Marcel Holtmann55594352013-10-06 16:11:57 -07002136unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002137 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002138 return err;
2139}
Johan Hedberg72a734e2010-12-30 00:38:22 +02002140
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002141static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
2142 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002143{
2144 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002145 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03002146 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002147 int err;
2148
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002149 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002150
Johan Hedberge6fe7982013-10-02 15:45:22 +03002151 status = mgmt_bredr_support(hdev);
2152 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002153 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2154 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03002155
Johan Hedberga7e80f22013-01-09 16:05:19 +02002156 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002157 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2158 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002159
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002160 hci_dev_lock(hdev);
2161
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002162 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02002163 bool changed = false;
2164
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002165 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07002166 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02002167 changed = true;
2168 }
2169
2170 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
2171 if (err < 0)
2172 goto failed;
2173
2174 if (changed)
2175 err = new_settings(hdev, sk);
2176
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002177 goto failed;
2178 }
2179
Johan Hedberg333ae952015-03-17 13:48:47 +02002180 if (pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002181 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2182 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002183 goto failed;
2184 }
2185
2186 val = !!cp->val;
2187
2188 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
2189 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
2190 goto failed;
2191 }
2192
2193 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
2194 if (!cmd) {
2195 err = -ENOMEM;
2196 goto failed;
2197 }
2198
2199 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
2200 if (err < 0) {
2201 mgmt_pending_remove(cmd);
2202 goto failed;
2203 }
2204
2205failed:
2206 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002207 return err;
2208}
2209
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002210static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002211{
2212 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002213 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07002214 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002215 int err;
2216
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002217 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002218
Marcel Holtmanncdba5282013-10-02 21:31:52 -07002219 status = mgmt_bredr_support(hdev);
2220 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002221 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07002222
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002223 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002224 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2225 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002226
Johan Hedberga7e80f22013-01-09 16:05:19 +02002227 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002228 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2229 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002230
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002231 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02002232
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002233 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002234 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02002235
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002236 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07002237 changed = !hci_dev_test_and_set_flag(hdev,
2238 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002239 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002240 changed = hci_dev_test_and_clear_flag(hdev,
2241 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002242 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002243 changed = hci_dev_test_and_clear_flag(hdev,
2244 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002245 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002246 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02002247 }
2248
2249 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
2250 if (err < 0)
2251 goto failed;
2252
2253 if (changed)
2254 err = new_settings(hdev, sk);
2255
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002256 goto failed;
2257 }
2258
Johan Hedberg333ae952015-03-17 13:48:47 +02002259 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002260 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2261 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002262 goto failed;
2263 }
2264
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002265 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002266 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
2267 goto failed;
2268 }
2269
2270 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
2271 if (!cmd) {
2272 err = -ENOMEM;
2273 goto failed;
2274 }
2275
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002276 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03002277 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
2278 sizeof(cp->val), &cp->val);
2279
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07002280 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002281 if (err < 0) {
2282 mgmt_pending_remove(cmd);
2283 goto failed;
2284 }
2285
2286failed:
2287 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002288 return err;
2289}
2290
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002291static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002292{
2293 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07002294 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03002295 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07002296 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002297
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002298 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002299
Johan Hedberge6fe7982013-10-02 15:45:22 +03002300 status = mgmt_bredr_support(hdev);
2301 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002302 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002303
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002304 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002305 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2306 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002307
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002308 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02002309 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2310 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002311
Johan Hedberga7e80f22013-01-09 16:05:19 +02002312 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002313 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2314 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002315
Marcel Holtmannee392692013-10-01 22:59:23 -07002316 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002317
Johan Hedberg333ae952015-03-17 13:48:47 +02002318 if (pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002319 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2320 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02002321 goto unlock;
2322 }
2323
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002324 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07002325 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002326 } else {
2327 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002328 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2329 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002330 goto unlock;
2331 }
2332
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002333 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002334 }
Marcel Holtmannee392692013-10-01 22:59:23 -07002335
2336 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
2337 if (err < 0)
2338 goto unlock;
2339
2340 if (changed)
2341 err = new_settings(hdev, sk);
2342
2343unlock:
2344 hci_dev_unlock(hdev);
2345 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002346}
2347
Marcel Holtmann1904a852015-01-11 13:50:44 -08002348static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002349{
2350 struct cmd_lookup match = { NULL, hdev };
2351
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302352 hci_dev_lock(hdev);
2353
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002354 if (status) {
2355 u8 mgmt_err = mgmt_status(status);
2356
2357 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
2358 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302359 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002360 }
2361
2362 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
2363
2364 new_settings(hdev, match.sk);
2365
2366 if (match.sk)
2367 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002368
2369 /* Make sure the controller has a good default for
2370 * advertising data. Restrict the update to when LE
2371 * has actually been enabled. During power on, the
2372 * update in powered_update_hci will take care of it.
2373 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002374 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002375 struct hci_request req;
2376
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002377 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07002378 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07002379 update_scan_rsp_data(&req);
Johan Hedberg2cf22212014-12-19 22:26:00 +02002380 __hci_update_background_scan(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002381 hci_req_run(&req, NULL);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002382 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302383
2384unlock:
2385 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002386}
2387
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002388static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002389{
2390 struct mgmt_mode *cp = data;
2391 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002392 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002393 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002394 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002395 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002396
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002397 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002398
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002399 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002400 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2401 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002402
Johan Hedberga7e80f22013-01-09 16:05:19 +02002403 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002404 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2405 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002406
Johan Hedbergc73eee92013-04-19 18:35:21 +03002407 /* LE-only devices do not allow toggling LE on/off */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002408 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02002409 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2410 MGMT_STATUS_REJECTED);
Johan Hedbergc73eee92013-04-19 18:35:21 +03002411
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002412 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002413
2414 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02002415 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002416
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002417 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02002418 bool changed = false;
2419
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002420 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07002421 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002422 changed = true;
2423 }
2424
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002425 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002426 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03002427 changed = true;
2428 }
2429
Johan Hedberg06199cf2012-02-22 16:37:11 +02002430 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
2431 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08002432 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002433
2434 if (changed)
2435 err = new_settings(hdev, sk);
2436
Johan Hedberg1de028c2012-02-29 19:55:35 -08002437 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002438 }
2439
Johan Hedberg333ae952015-03-17 13:48:47 +02002440 if (pending_find(MGMT_OP_SET_LE, hdev) ||
2441 pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002442 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2443 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002444 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002445 }
2446
2447 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
2448 if (!cmd) {
2449 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08002450 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002451 }
2452
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002453 hci_req_init(&req, hdev);
2454
Johan Hedberg06199cf2012-02-22 16:37:11 +02002455 memset(&hci_cp, 0, sizeof(hci_cp));
2456
2457 if (val) {
2458 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02002459 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002460 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002461 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002462 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002463 }
2464
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002465 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
2466 &hci_cp);
2467
2468 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05302469 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002470 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002471
Johan Hedberg1de028c2012-02-29 19:55:35 -08002472unlock:
2473 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002474 return err;
2475}
2476
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002477/* This is a helper function to test for pending mgmt commands that can
2478 * cause CoD or EIR HCI commands. We can only allow one such pending
2479 * mgmt command at a time since otherwise we cannot easily track what
2480 * the current values are, will be, and based on that calculate if a new
2481 * HCI command needs to be sent and if yes with what value.
2482 */
2483static bool pending_eir_or_class(struct hci_dev *hdev)
2484{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002485 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002486
2487 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2488 switch (cmd->opcode) {
2489 case MGMT_OP_ADD_UUID:
2490 case MGMT_OP_REMOVE_UUID:
2491 case MGMT_OP_SET_DEV_CLASS:
2492 case MGMT_OP_SET_POWERED:
2493 return true;
2494 }
2495 }
2496
2497 return false;
2498}
2499
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002500static const u8 bluetooth_base_uuid[] = {
2501 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2502 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2503};
2504
2505static u8 get_uuid_size(const u8 *uuid)
2506{
2507 u32 val;
2508
2509 if (memcmp(uuid, bluetooth_base_uuid, 12))
2510 return 128;
2511
2512 val = get_unaligned_le32(&uuid[12]);
2513 if (val > 0xffff)
2514 return 32;
2515
2516 return 16;
2517}
2518
Johan Hedberg92da6092013-03-15 17:06:55 -05002519static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2520{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002521 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002522
2523 hci_dev_lock(hdev);
2524
Johan Hedberg333ae952015-03-17 13:48:47 +02002525 cmd = pending_find(mgmt_op, hdev);
Johan Hedberg92da6092013-03-15 17:06:55 -05002526 if (!cmd)
2527 goto unlock;
2528
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002529 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2530 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002531
2532 mgmt_pending_remove(cmd);
2533
2534unlock:
2535 hci_dev_unlock(hdev);
2536}
2537
Marcel Holtmann1904a852015-01-11 13:50:44 -08002538static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002539{
2540 BT_DBG("status 0x%02x", status);
2541
2542 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2543}
2544
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002545static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002546{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002547 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002548 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002549 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002550 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002551 int err;
2552
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002553 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002554
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002555 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002556
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002557 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002558 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2559 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002560 goto failed;
2561 }
2562
Andre Guedes92c4c202012-06-07 19:05:44 -03002563 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002564 if (!uuid) {
2565 err = -ENOMEM;
2566 goto failed;
2567 }
2568
2569 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002570 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002571 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002572
Johan Hedbergde66aa62013-01-27 00:31:27 +02002573 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002574
Johan Hedberg890ea892013-03-15 17:06:52 -05002575 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002576
Johan Hedberg890ea892013-03-15 17:06:52 -05002577 update_class(&req);
2578 update_eir(&req);
2579
Johan Hedberg92da6092013-03-15 17:06:55 -05002580 err = hci_req_run(&req, add_uuid_complete);
2581 if (err < 0) {
2582 if (err != -ENODATA)
2583 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002584
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002585 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2586 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002587 goto failed;
2588 }
2589
2590 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002591 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002592 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002593 goto failed;
2594 }
2595
2596 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002597
2598failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002599 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002600 return err;
2601}
2602
Johan Hedberg24b78d02012-02-23 23:24:30 +02002603static bool enable_service_cache(struct hci_dev *hdev)
2604{
2605 if (!hdev_is_powered(hdev))
2606 return false;
2607
Marcel Holtmann238be782015-03-13 02:11:06 -07002608 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002609 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2610 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002611 return true;
2612 }
2613
2614 return false;
2615}
2616
Marcel Holtmann1904a852015-01-11 13:50:44 -08002617static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002618{
2619 BT_DBG("status 0x%02x", status);
2620
2621 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2622}
2623
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002624static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002625 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002626{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002627 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002628 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002629 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002630 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 -05002631 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002632 int err, found;
2633
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002634 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002635
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002636 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002637
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002638 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002639 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2640 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002641 goto unlock;
2642 }
2643
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002644 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002645 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002646
Johan Hedberg24b78d02012-02-23 23:24:30 +02002647 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002648 err = mgmt_cmd_complete(sk, hdev->id,
2649 MGMT_OP_REMOVE_UUID,
2650 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002651 goto unlock;
2652 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002653
Johan Hedberg9246a862012-02-23 21:33:16 +02002654 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002655 }
2656
2657 found = 0;
2658
Johan Hedberg056341c2013-01-27 00:31:30 +02002659 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002660 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2661 continue;
2662
2663 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002664 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002665 found++;
2666 }
2667
2668 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002669 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2670 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002671 goto unlock;
2672 }
2673
Johan Hedberg9246a862012-02-23 21:33:16 +02002674update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002675 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002676
Johan Hedberg890ea892013-03-15 17:06:52 -05002677 update_class(&req);
2678 update_eir(&req);
2679
Johan Hedberg92da6092013-03-15 17:06:55 -05002680 err = hci_req_run(&req, remove_uuid_complete);
2681 if (err < 0) {
2682 if (err != -ENODATA)
2683 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002684
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002685 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2686 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002687 goto unlock;
2688 }
2689
2690 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002691 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002692 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002693 goto unlock;
2694 }
2695
2696 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002697
2698unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002699 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002700 return err;
2701}
2702
Marcel Holtmann1904a852015-01-11 13:50:44 -08002703static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002704{
2705 BT_DBG("status 0x%02x", status);
2706
2707 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2708}
2709
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002710static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002711 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002712{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002713 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002714 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002715 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002716 int err;
2717
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002718 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002719
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002720 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002721 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2722 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002723
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002724 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002725
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002726 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002727 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2728 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002729 goto unlock;
2730 }
2731
2732 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002733 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2734 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002735 goto unlock;
2736 }
2737
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002738 hdev->major_class = cp->major;
2739 hdev->minor_class = cp->minor;
2740
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002741 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002742 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2743 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002744 goto unlock;
2745 }
2746
Johan Hedberg890ea892013-03-15 17:06:52 -05002747 hci_req_init(&req, hdev);
2748
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002749 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002750 hci_dev_unlock(hdev);
2751 cancel_delayed_work_sync(&hdev->service_cache);
2752 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002753 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002754 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002755
Johan Hedberg890ea892013-03-15 17:06:52 -05002756 update_class(&req);
2757
Johan Hedberg92da6092013-03-15 17:06:55 -05002758 err = hci_req_run(&req, set_class_complete);
2759 if (err < 0) {
2760 if (err != -ENODATA)
2761 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002762
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002763 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2764 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002765 goto unlock;
2766 }
2767
2768 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002769 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002770 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002771 goto unlock;
2772 }
2773
2774 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002775
Johan Hedbergb5235a62012-02-21 14:32:24 +02002776unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002777 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002778 return err;
2779}
2780
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002781static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002782 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002783{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002784 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002785 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2786 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002787 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002788 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002789 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002790
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002791 BT_DBG("request for %s", hdev->name);
2792
2793 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002794 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2795 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002796
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002797 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002798 if (key_count > max_key_count) {
2799 BT_ERR("load_link_keys: too big key_count value %u",
2800 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002801 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2802 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002803 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002804
Johan Hedberg86742e12011-11-07 23:13:38 +02002805 expected_len = sizeof(*cp) + key_count *
2806 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002807 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002808 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002809 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002810 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2811 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002812 }
2813
Johan Hedberg4ae14302013-01-20 14:27:13 +02002814 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002815 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2816 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002817
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002818 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002819 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002820
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002821 for (i = 0; i < key_count; i++) {
2822 struct mgmt_link_key_info *key = &cp->keys[i];
2823
Marcel Holtmann8e991132014-01-10 02:07:25 -08002824 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002825 return mgmt_cmd_status(sk, hdev->id,
2826 MGMT_OP_LOAD_LINK_KEYS,
2827 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002828 }
2829
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002830 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002831
2832 hci_link_keys_clear(hdev);
2833
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002834 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002835 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002836 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002837 changed = hci_dev_test_and_clear_flag(hdev,
2838 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002839
2840 if (changed)
2841 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002842
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002843 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002844 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002845
Johan Hedberg58e92932014-06-24 14:00:26 +03002846 /* Always ignore debug keys and require a new pairing if
2847 * the user wants to use them.
2848 */
2849 if (key->type == HCI_LK_DEBUG_COMBINATION)
2850 continue;
2851
Johan Hedberg7652ff62014-06-24 13:15:49 +03002852 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2853 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002854 }
2855
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002856 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002857
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002858 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002859
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002860 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002861}
2862
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002863static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002864 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002865{
2866 struct mgmt_ev_device_unpaired ev;
2867
2868 bacpy(&ev.addr.bdaddr, bdaddr);
2869 ev.addr.type = addr_type;
2870
2871 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002872 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002873}
2874
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002875static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002876 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002877{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002878 struct mgmt_cp_unpair_device *cp = data;
2879 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002880 struct hci_cp_disconnect dc;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002881 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002882 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002883 int err;
2884
Johan Hedberga8a1d192011-11-10 15:54:38 +02002885 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002886 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2887 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002888
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002889 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002890 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2891 MGMT_STATUS_INVALID_PARAMS,
2892 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002893
Johan Hedberg118da702013-01-20 14:27:20 +02002894 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002895 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2896 MGMT_STATUS_INVALID_PARAMS,
2897 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002898
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002899 hci_dev_lock(hdev);
2900
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002901 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002902 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2903 MGMT_STATUS_NOT_POWERED, &rp,
2904 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002905 goto unlock;
2906 }
2907
Johan Hedberge0b2b272014-02-18 17:14:31 +02002908 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002909 /* If disconnection is requested, then look up the
2910 * connection. If the remote device is connected, it
2911 * will be later used to terminate the link.
2912 *
2913 * Setting it to NULL explicitly will cause no
2914 * termination of the link.
2915 */
2916 if (cp->disconnect)
2917 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2918 &cp->addr.bdaddr);
2919 else
2920 conn = NULL;
2921
Johan Hedberg124f6e32012-02-09 13:50:12 +02002922 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedberge0b2b272014-02-18 17:14:31 +02002923 } else {
2924 u8 addr_type;
2925
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002926 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
2927 &cp->addr.bdaddr);
2928 if (conn) {
2929 /* Defer clearing up the connection parameters
2930 * until closing to give a chance of keeping
2931 * them if a repairing happens.
2932 */
2933 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2934
2935 /* If disconnection is not requested, then
2936 * clear the connection variable so that the
2937 * link is not terminated.
2938 */
2939 if (!cp->disconnect)
2940 conn = NULL;
2941 }
2942
Johan Hedberge0b2b272014-02-18 17:14:31 +02002943 if (cp->addr.type == BDADDR_LE_PUBLIC)
2944 addr_type = ADDR_LE_DEV_PUBLIC;
2945 else
2946 addr_type = ADDR_LE_DEV_RANDOM;
2947
Johan Hedberga7ec7332014-02-18 17:14:35 +02002948 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2949
Johan Hedberge0b2b272014-02-18 17:14:31 +02002950 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
2951 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002952
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002953 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002954 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2955 MGMT_STATUS_NOT_PAIRED, &rp,
2956 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002957 goto unlock;
2958 }
2959
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002960 /* If the connection variable is set, then termination of the
2961 * link is requested.
2962 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002963 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002964 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2965 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002966 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002967 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002968 }
2969
Johan Hedberg124f6e32012-02-09 13:50:12 +02002970 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002971 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002972 if (!cmd) {
2973 err = -ENOMEM;
2974 goto unlock;
2975 }
2976
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002977 cmd->cmd_complete = addr_cmd_complete;
2978
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002979 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002980 dc.reason = 0x13; /* Remote User Terminated Connection */
2981 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2982 if (err < 0)
2983 mgmt_pending_remove(cmd);
2984
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002985unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002986 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002987 return err;
2988}
2989
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002990static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002991 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002992{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002993 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002994 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002995 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002996 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002997 int err;
2998
2999 BT_DBG("");
3000
Johan Hedberg06a63b12013-01-20 14:27:21 +02003001 memset(&rp, 0, sizeof(rp));
3002 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3003 rp.addr.type = cp->addr.type;
3004
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003005 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003006 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
3007 MGMT_STATUS_INVALID_PARAMS,
3008 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003009
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003010 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003011
3012 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003013 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
3014 MGMT_STATUS_NOT_POWERED, &rp,
3015 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003016 goto failed;
3017 }
3018
Johan Hedberg333ae952015-03-17 13:48:47 +02003019 if (pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003020 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
3021 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003022 goto failed;
3023 }
3024
Andre Guedes591f47f2012-04-24 21:02:49 -03003025 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003026 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
3027 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02003028 else
3029 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03003030
Vishal Agarwalf9607272012-06-13 05:32:43 +05303031 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003032 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
3033 MGMT_STATUS_NOT_CONNECTED, &rp,
3034 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003035 goto failed;
3036 }
3037
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003038 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03003039 if (!cmd) {
3040 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003041 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03003042 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02003043
Johan Hedbergf5818c22014-12-05 13:36:02 +02003044 cmd->cmd_complete = generic_cmd_complete;
3045
Johan Hedberge3f2f922014-08-18 20:33:33 +03003046 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003047 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03003048 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003049
3050failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003051 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003052 return err;
3053}
3054
Andre Guedes57c14772012-04-24 21:02:50 -03003055static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02003056{
3057 switch (link_type) {
3058 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02003059 switch (addr_type) {
3060 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03003061 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03003062
Johan Hedberg48264f02011-11-09 13:58:58 +02003063 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03003064 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03003065 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02003066 }
Andre Guedes0ed09142012-04-03 08:46:54 -03003067
Johan Hedberg4c659c32011-11-07 23:13:39 +02003068 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03003069 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03003070 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02003071 }
3072}
3073
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003074static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
3075 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02003076{
Johan Hedberg2784eb42011-01-21 13:56:35 +02003077 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02003078 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02003079 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003080 int err;
3081 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02003082
3083 BT_DBG("");
3084
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003085 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003086
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003087 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003088 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
3089 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003090 goto unlock;
3091 }
3092
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003093 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02003094 list_for_each_entry(c, &hdev->conn_hash.list, list) {
3095 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003096 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02003097 }
3098
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003099 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03003100 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02003101 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02003102 err = -ENOMEM;
3103 goto unlock;
3104 }
3105
Johan Hedberg2784eb42011-01-21 13:56:35 +02003106 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02003107 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02003108 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
3109 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02003110 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03003111 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03003112 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02003113 continue;
3114 i++;
3115 }
3116
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003117 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003118
Johan Hedberg4c659c32011-11-07 23:13:39 +02003119 /* Recalculate length in case of filtered SCO connections, etc */
3120 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02003121
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003122 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
3123 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003124
Johan Hedberga38528f2011-01-22 06:46:43 +02003125 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003126
3127unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003128 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003129 return err;
3130}
3131
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003132static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003133 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003134{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003135 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003136 int err;
3137
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003138 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003139 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003140 if (!cmd)
3141 return -ENOMEM;
3142
Johan Hedbergd8457692012-02-17 14:24:57 +02003143 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003144 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003145 if (err < 0)
3146 mgmt_pending_remove(cmd);
3147
3148 return err;
3149}
3150
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003151static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003152 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003153{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003154 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003155 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003156 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003157 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003158 int err;
3159
3160 BT_DBG("");
3161
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003162 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003163
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003164 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003165 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3166 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003167 goto failed;
3168 }
3169
Johan Hedbergd8457692012-02-17 14:24:57 +02003170 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003171 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003172 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3173 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003174 goto failed;
3175 }
3176
3177 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02003178 struct mgmt_cp_pin_code_neg_reply ncp;
3179
3180 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003181
3182 BT_ERR("PIN code is not 16 bytes long");
3183
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003184 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003185 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02003186 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3187 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003188
3189 goto failed;
3190 }
3191
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03003192 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03003193 if (!cmd) {
3194 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003195 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03003196 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02003197
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003198 cmd->cmd_complete = addr_cmd_complete;
3199
Johan Hedbergd8457692012-02-17 14:24:57 +02003200 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003201 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02003202 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003203
3204 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
3205 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03003206 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003207
3208failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003209 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003210 return err;
3211}
3212
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003213static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
3214 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003215{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003216 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003217
3218 BT_DBG("");
3219
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003220 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003221 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
3222 MGMT_STATUS_INVALID_PARAMS, NULL, 0);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003223
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003224 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003225
3226 hdev->io_capability = cp->io_capability;
3227
3228 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003229 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003230
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003231 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003232
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003233 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
3234 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003235}
3236
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003237static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003238{
3239 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003240 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003241
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003242 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03003243 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
3244 continue;
3245
Johan Hedberge9a416b2011-02-19 12:05:56 -03003246 if (cmd->user_data != conn)
3247 continue;
3248
3249 return cmd;
3250 }
3251
3252 return NULL;
3253}
3254
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003255static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003256{
3257 struct mgmt_rp_pair_device rp;
3258 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02003259 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003260
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02003261 bacpy(&rp.addr.bdaddr, &conn->dst);
3262 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003263
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003264 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
3265 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003266
3267 /* So we don't get further callbacks for this connection */
3268 conn->connect_cfm_cb = NULL;
3269 conn->security_cfm_cb = NULL;
3270 conn->disconn_cfm_cb = NULL;
3271
David Herrmann76a68ba2013-04-06 20:28:37 +02003272 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00003273
3274 /* The device is paired so there is no need to remove
3275 * its connection parameters anymore.
3276 */
3277 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02003278
3279 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02003280
3281 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003282}
3283
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003284void mgmt_smp_complete(struct hci_conn *conn, bool complete)
3285{
3286 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003287 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003288
3289 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003290 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02003291 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02003292 mgmt_pending_remove(cmd);
3293 }
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003294}
3295
Johan Hedberge9a416b2011-02-19 12:05:56 -03003296static void pairing_complete_cb(struct hci_conn *conn, u8 status)
3297{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003298 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003299
3300 BT_DBG("status %u", status);
3301
Johan Hedberg56e5cb82011-11-08 20:40:16 +02003302 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003303 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02003304 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02003305 return;
3306 }
3307
3308 cmd->cmd_complete(cmd, mgmt_status(status));
3309 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003310}
3311
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003312static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303313{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003314 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303315
3316 BT_DBG("status %u", status);
3317
3318 if (!status)
3319 return;
3320
3321 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003322 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303323 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02003324 return;
3325 }
3326
3327 cmd->cmd_complete(cmd, mgmt_status(status));
3328 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303329}
3330
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003331static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003332 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003333{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003334 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02003335 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003336 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003337 u8 sec_level, auth_type;
3338 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003339 int err;
3340
3341 BT_DBG("");
3342
Szymon Jancf950a30e2013-01-18 12:48:07 +01003343 memset(&rp, 0, sizeof(rp));
3344 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3345 rp.addr.type = cp->addr.type;
3346
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003347 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003348 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3349 MGMT_STATUS_INVALID_PARAMS,
3350 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003351
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003352 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003353 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3354 MGMT_STATUS_INVALID_PARAMS,
3355 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003356
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003357 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003358
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003359 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003360 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3361 MGMT_STATUS_NOT_POWERED, &rp,
3362 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003363 goto unlock;
3364 }
3365
Johan Hedberg55e76b32015-03-10 22:34:40 +02003366 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
3367 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3368 MGMT_STATUS_ALREADY_PAIRED, &rp,
3369 sizeof(rp));
3370 goto unlock;
3371 }
3372
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03003373 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02003374 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003375
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003376 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03003377 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
3378 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003379 } else {
3380 u8 addr_type;
3381
3382 /* Convert from L2CAP channel address type to HCI address type
3383 */
3384 if (cp->addr.type == BDADDR_LE_PUBLIC)
3385 addr_type = ADDR_LE_DEV_PUBLIC;
3386 else
3387 addr_type = ADDR_LE_DEV_RANDOM;
3388
Marcel Holtmann7c264b12014-06-30 12:34:40 +02003389 /* When pairing a new device, it is expected to remember
3390 * this device for future connections. Adding the connection
3391 * parameter information ahead of time allows tracking
3392 * of the slave preferred values and will speed up any
3393 * further connection establishment.
3394 *
3395 * If connection parameters already exist, then they
3396 * will be kept and this function does nothing.
3397 */
3398 hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
3399
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003400 conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type,
Johan Hedberge804d252014-07-16 11:42:28 +03003401 sec_level, HCI_LE_CONN_TIMEOUT,
3402 HCI_ROLE_MASTER);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003403 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003404
Ville Tervo30e76272011-02-22 16:10:53 -03003405 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003406 int status;
3407
3408 if (PTR_ERR(conn) == -EBUSY)
3409 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01003410 else if (PTR_ERR(conn) == -EOPNOTSUPP)
3411 status = MGMT_STATUS_NOT_SUPPORTED;
3412 else if (PTR_ERR(conn) == -ECONNREFUSED)
3413 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003414 else
3415 status = MGMT_STATUS_CONNECT_FAILED;
3416
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003417 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3418 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003419 goto unlock;
3420 }
3421
3422 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02003423 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003424 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3425 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003426 goto unlock;
3427 }
3428
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003429 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003430 if (!cmd) {
3431 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02003432 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003433 goto unlock;
3434 }
3435
Johan Hedberg04ab2742014-12-05 13:36:04 +02003436 cmd->cmd_complete = pairing_complete;
3437
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003438 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003439 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003440 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02003441 conn->security_cfm_cb = pairing_complete_cb;
3442 conn->disconn_cfm_cb = pairing_complete_cb;
3443 } else {
3444 conn->connect_cfm_cb = le_pairing_complete_cb;
3445 conn->security_cfm_cb = le_pairing_complete_cb;
3446 conn->disconn_cfm_cb = le_pairing_complete_cb;
3447 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003448
Johan Hedberge9a416b2011-02-19 12:05:56 -03003449 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003450 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003451
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003452 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003453 hci_conn_security(conn, sec_level, auth_type, true)) {
3454 cmd->cmd_complete(cmd, 0);
3455 mgmt_pending_remove(cmd);
3456 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003457
3458 err = 0;
3459
3460unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003461 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003462 return err;
3463}
3464
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003465static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3466 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003467{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003468 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003469 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003470 struct hci_conn *conn;
3471 int err;
3472
3473 BT_DBG("");
3474
Johan Hedberg28424702012-02-02 04:02:29 +02003475 hci_dev_lock(hdev);
3476
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003477 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003478 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3479 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003480 goto unlock;
3481 }
3482
Johan Hedberg333ae952015-03-17 13:48:47 +02003483 cmd = pending_find(MGMT_OP_PAIR_DEVICE, hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003484 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003485 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3486 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003487 goto unlock;
3488 }
3489
3490 conn = cmd->user_data;
3491
3492 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003493 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3494 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003495 goto unlock;
3496 }
3497
Johan Hedberga511b352014-12-11 21:45:45 +02003498 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3499 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003500
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003501 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3502 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003503unlock:
3504 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003505 return err;
3506}
3507
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003508static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003509 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003510 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003511{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003512 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003513 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003514 int err;
3515
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003516 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003517
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003518 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003519 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3520 MGMT_STATUS_NOT_POWERED, addr,
3521 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003522 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003523 }
3524
Johan Hedberg1707c602013-03-15 17:07:15 -05003525 if (addr->type == BDADDR_BREDR)
3526 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003527 else
Johan Hedberg1707c602013-03-15 17:07:15 -05003528 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08003529
Johan Hedberg272d90d2012-02-09 15:26:12 +02003530 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003531 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3532 MGMT_STATUS_NOT_CONNECTED, addr,
3533 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003534 goto done;
3535 }
3536
Johan Hedberg1707c602013-03-15 17:07:15 -05003537 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003538 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003539 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003540 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3541 MGMT_STATUS_SUCCESS, addr,
3542 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003543 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003544 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3545 MGMT_STATUS_FAILED, addr,
3546 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003547
Brian Gix47c15e22011-11-16 13:53:14 -08003548 goto done;
3549 }
3550
Johan Hedberg1707c602013-03-15 17:07:15 -05003551 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003552 if (!cmd) {
3553 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003554 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003555 }
3556
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003557 cmd->cmd_complete = addr_cmd_complete;
3558
Brian Gix0df4c182011-11-16 13:53:13 -08003559 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003560 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3561 struct hci_cp_user_passkey_reply cp;
3562
Johan Hedberg1707c602013-03-15 17:07:15 -05003563 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003564 cp.passkey = passkey;
3565 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3566 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003567 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3568 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003569
Johan Hedberga664b5b2011-02-19 12:06:02 -03003570 if (err < 0)
3571 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003572
Brian Gix0df4c182011-11-16 13:53:13 -08003573done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003574 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003575 return err;
3576}
3577
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303578static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3579 void *data, u16 len)
3580{
3581 struct mgmt_cp_pin_code_neg_reply *cp = data;
3582
3583 BT_DBG("");
3584
Johan Hedberg1707c602013-03-15 17:07:15 -05003585 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303586 MGMT_OP_PIN_CODE_NEG_REPLY,
3587 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3588}
3589
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003590static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3591 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003592{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003593 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003594
3595 BT_DBG("");
3596
3597 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003598 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3599 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003600
Johan Hedberg1707c602013-03-15 17:07:15 -05003601 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003602 MGMT_OP_USER_CONFIRM_REPLY,
3603 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003604}
3605
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003606static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003607 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003608{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003609 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003610
3611 BT_DBG("");
3612
Johan Hedberg1707c602013-03-15 17:07:15 -05003613 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003614 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3615 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003616}
3617
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003618static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3619 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003620{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003621 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003622
3623 BT_DBG("");
3624
Johan Hedberg1707c602013-03-15 17:07:15 -05003625 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003626 MGMT_OP_USER_PASSKEY_REPLY,
3627 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003628}
3629
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003630static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003631 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003632{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003633 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003634
3635 BT_DBG("");
3636
Johan Hedberg1707c602013-03-15 17:07:15 -05003637 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003638 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3639 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003640}
3641
Johan Hedberg13928972013-03-15 17:07:00 -05003642static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003643{
Johan Hedberg13928972013-03-15 17:07:00 -05003644 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003645 struct hci_cp_write_local_name cp;
3646
Johan Hedberg13928972013-03-15 17:07:00 -05003647 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003648
Johan Hedberg890ea892013-03-15 17:06:52 -05003649 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003650}
3651
Marcel Holtmann1904a852015-01-11 13:50:44 -08003652static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003653{
3654 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003655 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003656
3657 BT_DBG("status 0x%02x", status);
3658
3659 hci_dev_lock(hdev);
3660
Johan Hedberg333ae952015-03-17 13:48:47 +02003661 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003662 if (!cmd)
3663 goto unlock;
3664
3665 cp = cmd->param;
3666
3667 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003668 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3669 mgmt_status(status));
Johan Hedberg13928972013-03-15 17:07:00 -05003670 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003671 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3672 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003673
3674 mgmt_pending_remove(cmd);
3675
3676unlock:
3677 hci_dev_unlock(hdev);
3678}
3679
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003680static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003681 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003682{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003683 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003684 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003685 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003686 int err;
3687
3688 BT_DBG("");
3689
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003690 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003691
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003692 /* If the old values are the same as the new ones just return a
3693 * direct command complete event.
3694 */
3695 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3696 !memcmp(hdev->short_name, cp->short_name,
3697 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003698 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3699 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003700 goto failed;
3701 }
3702
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003703 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003704
Johan Hedbergb5235a62012-02-21 14:32:24 +02003705 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003706 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003707
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003708 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3709 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003710 if (err < 0)
3711 goto failed;
3712
Marcel Holtmannf6b77122015-03-14 19:28:05 -07003713 err = mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev,
3714 data, len, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003715
Johan Hedbergb5235a62012-02-21 14:32:24 +02003716 goto failed;
3717 }
3718
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003719 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003720 if (!cmd) {
3721 err = -ENOMEM;
3722 goto failed;
3723 }
3724
Johan Hedberg13928972013-03-15 17:07:00 -05003725 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3726
Johan Hedberg890ea892013-03-15 17:06:52 -05003727 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003728
3729 if (lmp_bredr_capable(hdev)) {
3730 update_name(&req);
3731 update_eir(&req);
3732 }
3733
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003734 /* The name is stored in the scan response data and so
3735 * no need to udpate the advertising data here.
3736 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003737 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003738 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003739
Johan Hedberg13928972013-03-15 17:07:00 -05003740 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003741 if (err < 0)
3742 mgmt_pending_remove(cmd);
3743
3744failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003745 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003746 return err;
3747}
3748
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003749static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003750 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003751{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003752 struct mgmt_pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01003753 int err;
3754
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003755 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003756
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003757 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003758
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003759 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003760 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3761 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003762 goto unlock;
3763 }
3764
Andre Guedes9a1a1992012-07-24 15:03:48 -03003765 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003766 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3767 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003768 goto unlock;
3769 }
3770
Johan Hedberg333ae952015-03-17 13:48:47 +02003771 if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003772 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3773 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003774 goto unlock;
3775 }
3776
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003777 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003778 if (!cmd) {
3779 err = -ENOMEM;
3780 goto unlock;
3781 }
3782
Johan Hedberg710f11c2014-05-26 11:21:22 +03003783 if (bredr_sc_enabled(hdev))
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003784 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
3785 0, NULL);
3786 else
3787 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3788
Szymon Jancc35938b2011-03-22 13:12:21 +01003789 if (err < 0)
3790 mgmt_pending_remove(cmd);
3791
3792unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003793 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003794 return err;
3795}
3796
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003797static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003798 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003799{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003800 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003801 int err;
3802
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003803 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003804
Johan Hedberg5d57e792015-01-23 10:10:38 +02003805 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003806 return mgmt_cmd_complete(sk, hdev->id,
3807 MGMT_OP_ADD_REMOTE_OOB_DATA,
3808 MGMT_STATUS_INVALID_PARAMS,
3809 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003810
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003811 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003812
Marcel Holtmannec109112014-01-10 02:07:30 -08003813 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3814 struct mgmt_cp_add_remote_oob_data *cp = data;
3815 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003816
Johan Hedbergc19a4952014-11-17 20:52:19 +02003817 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003818 err = mgmt_cmd_complete(sk, hdev->id,
3819 MGMT_OP_ADD_REMOTE_OOB_DATA,
3820 MGMT_STATUS_INVALID_PARAMS,
3821 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003822 goto unlock;
3823 }
3824
Marcel Holtmannec109112014-01-10 02:07:30 -08003825 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003826 cp->addr.type, cp->hash,
3827 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003828 if (err < 0)
3829 status = MGMT_STATUS_FAILED;
3830 else
3831 status = MGMT_STATUS_SUCCESS;
3832
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003833 err = mgmt_cmd_complete(sk, hdev->id,
3834 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3835 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003836 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3837 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003838 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003839 u8 status;
3840
Johan Hedberg86df9202014-10-26 20:52:27 +01003841 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003842 /* Enforce zero-valued 192-bit parameters as
3843 * long as legacy SMP OOB isn't implemented.
3844 */
3845 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3846 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003847 err = mgmt_cmd_complete(sk, hdev->id,
3848 MGMT_OP_ADD_REMOTE_OOB_DATA,
3849 MGMT_STATUS_INVALID_PARAMS,
3850 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003851 goto unlock;
3852 }
3853
Johan Hedberg86df9202014-10-26 20:52:27 +01003854 rand192 = NULL;
3855 hash192 = NULL;
3856 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003857 /* In case one of the P-192 values is set to zero,
3858 * then just disable OOB data for P-192.
3859 */
3860 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3861 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3862 rand192 = NULL;
3863 hash192 = NULL;
3864 } else {
3865 rand192 = cp->rand192;
3866 hash192 = cp->hash192;
3867 }
3868 }
3869
3870 /* In case one of the P-256 values is set to zero, then just
3871 * disable OOB data for P-256.
3872 */
3873 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3874 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3875 rand256 = NULL;
3876 hash256 = NULL;
3877 } else {
3878 rand256 = cp->rand256;
3879 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003880 }
3881
Johan Hedberg81328d52014-10-26 20:33:47 +01003882 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003883 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003884 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003885 if (err < 0)
3886 status = MGMT_STATUS_FAILED;
3887 else
3888 status = MGMT_STATUS_SUCCESS;
3889
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003890 err = mgmt_cmd_complete(sk, hdev->id,
3891 MGMT_OP_ADD_REMOTE_OOB_DATA,
3892 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003893 } else {
3894 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003895 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3896 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003897 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003898
Johan Hedbergc19a4952014-11-17 20:52:19 +02003899unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003900 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003901 return err;
3902}
3903
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003904static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003905 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003906{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003907 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003908 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003909 int err;
3910
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003911 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003912
Johan Hedbergc19a4952014-11-17 20:52:19 +02003913 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003914 return mgmt_cmd_complete(sk, hdev->id,
3915 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3916 MGMT_STATUS_INVALID_PARAMS,
3917 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003918
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003919 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003920
Johan Hedbergeedbd582014-11-15 09:34:23 +02003921 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3922 hci_remote_oob_data_clear(hdev);
3923 status = MGMT_STATUS_SUCCESS;
3924 goto done;
3925 }
3926
Johan Hedberg6928a922014-10-26 20:46:09 +01003927 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003928 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003929 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003930 else
Szymon Janca6785be2012-12-13 15:11:21 +01003931 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003932
Johan Hedbergeedbd582014-11-15 09:34:23 +02003933done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003934 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3935 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003936
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003937 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003938 return err;
3939}
3940
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003941static bool trigger_bredr_inquiry(struct hci_request *req, u8 *status)
3942{
3943 struct hci_dev *hdev = req->hdev;
3944 struct hci_cp_inquiry cp;
3945 /* General inquiry access code (GIAC) */
3946 u8 lap[3] = { 0x33, 0x8b, 0x9e };
3947
3948 *status = mgmt_bredr_support(hdev);
3949 if (*status)
3950 return false;
3951
3952 if (hci_dev_test_flag(hdev, HCI_INQUIRY)) {
3953 *status = MGMT_STATUS_BUSY;
3954 return false;
3955 }
3956
3957 hci_inquiry_cache_flush(hdev);
3958
3959 memset(&cp, 0, sizeof(cp));
3960 memcpy(&cp.lap, lap, sizeof(cp.lap));
3961 cp.length = DISCOV_BREDR_INQUIRY_LEN;
3962
3963 hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp);
3964
3965 return true;
3966}
3967
3968static bool trigger_le_scan(struct hci_request *req, u16 interval, u8 *status)
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003969{
Marcel Holtmann80190442014-12-04 11:36:36 +01003970 struct hci_dev *hdev = req->hdev;
3971 struct hci_cp_le_set_scan_param param_cp;
3972 struct hci_cp_le_set_scan_enable enable_cp;
Marcel Holtmann80190442014-12-04 11:36:36 +01003973 u8 own_addr_type;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003974 int err;
3975
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003976 *status = mgmt_le_support(hdev);
3977 if (*status)
3978 return false;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003979
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003980 if (hci_dev_test_flag(hdev, HCI_LE_ADV)) {
3981 /* Don't let discovery abort an outgoing connection attempt
3982 * that's using directed advertising.
3983 */
3984 if (hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT)) {
3985 *status = MGMT_STATUS_REJECTED;
Marcel Holtmann80190442014-12-04 11:36:36 +01003986 return false;
3987 }
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003988
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003989 disable_advertising(req);
3990 }
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003991
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003992 /* If controller is scanning, it means the background scanning is
3993 * running. Thus, we should temporarily stop it in order to set the
3994 * discovery scanning parameters.
3995 */
3996 if (hci_dev_test_flag(hdev, HCI_LE_SCAN))
3997 hci_req_add_le_scan_disable(req);
3998
3999 /* All active scans will be done with either a resolvable private
4000 * address (when privacy feature has been enabled) or non-resolvable
4001 * private address.
4002 */
4003 err = hci_update_random_address(req, true, &own_addr_type);
4004 if (err < 0) {
4005 *status = MGMT_STATUS_FAILED;
4006 return false;
4007 }
4008
4009 memset(&param_cp, 0, sizeof(param_cp));
4010 param_cp.type = LE_SCAN_ACTIVE;
4011 param_cp.interval = cpu_to_le16(interval);
4012 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
4013 param_cp.own_address_type = own_addr_type;
4014
4015 hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
4016 &param_cp);
4017
4018 memset(&enable_cp, 0, sizeof(enable_cp));
4019 enable_cp.enable = LE_SCAN_ENABLE;
4020 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
4021
4022 hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
4023 &enable_cp);
4024
4025 return true;
4026}
4027
4028static bool trigger_discovery(struct hci_request *req, u8 *status)
4029{
4030 struct hci_dev *hdev = req->hdev;
4031
4032 switch (hdev->discovery.type) {
4033 case DISCOV_TYPE_BREDR:
4034 if (!trigger_bredr_inquiry(req, status))
4035 return false;
Marcel Holtmann80190442014-12-04 11:36:36 +01004036 break;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03004037
Marcel Holtmann80190442014-12-04 11:36:36 +01004038 case DISCOV_TYPE_INTERLEAVED:
Jakub Pawlowski07d23342015-03-17 09:04:14 -07004039 if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY,
4040 &hdev->quirks)) {
4041 /* During simultaneous discovery, we double LE scan
4042 * interval. We must leave some time for the controller
4043 * to do BR/EDR inquiry.
4044 */
4045 if (!trigger_le_scan(req, DISCOV_LE_SCAN_INT * 2,
4046 status))
4047 return false;
4048
4049 if (!trigger_bredr_inquiry(req, status))
4050 return false;
4051
4052 return true;
4053 }
4054
Jakub Pawlowski812abb12015-03-17 09:04:13 -07004055 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmann80190442014-12-04 11:36:36 +01004056 *status = MGMT_STATUS_NOT_SUPPORTED;
4057 return false;
4058 }
Jakub Pawlowski812abb12015-03-17 09:04:13 -07004059 /* fall through */
Marcel Holtmann80190442014-12-04 11:36:36 +01004060
Jakub Pawlowski812abb12015-03-17 09:04:13 -07004061 case DISCOV_TYPE_LE:
4062 if (!trigger_le_scan(req, DISCOV_LE_SCAN_INT, status))
Marcel Holtmann80190442014-12-04 11:36:36 +01004063 return false;
Marcel Holtmann80190442014-12-04 11:36:36 +01004064 break;
4065
4066 default:
4067 *status = MGMT_STATUS_INVALID_PARAMS;
4068 return false;
4069 }
4070
4071 return true;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03004072}
4073
Marcel Holtmann1904a852015-01-11 13:50:44 -08004074static void start_discovery_complete(struct hci_dev *hdev, u8 status,
4075 u16 opcode)
Andre Guedes7c307722013-04-30 15:29:28 -03004076{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004077 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004078 unsigned long timeout;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004079
Andre Guedes7c307722013-04-30 15:29:28 -03004080 BT_DBG("status %d", status);
4081
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004082 hci_dev_lock(hdev);
4083
Johan Hedberg333ae952015-03-17 13:48:47 +02004084 cmd = pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004085 if (!cmd)
Johan Hedberg333ae952015-03-17 13:48:47 +02004086 cmd = pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004087
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004088 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004089 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004090 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03004091 }
4092
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004093 if (status) {
4094 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
4095 goto unlock;
4096 }
4097
Andre Guedes7c307722013-04-30 15:29:28 -03004098 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
Andre Guedes7c307722013-04-30 15:29:28 -03004099
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004100 /* If the scan involves LE scan, pick proper timeout to schedule
4101 * hdev->le_scan_disable that will stop it.
4102 */
Andre Guedes7c307722013-04-30 15:29:28 -03004103 switch (hdev->discovery.type) {
4104 case DISCOV_TYPE_LE:
Lukasz Rymanowski3d5a76f2014-03-27 20:55:21 +01004105 timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03004106 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004107 case DISCOV_TYPE_INTERLEAVED:
Jakub Pawlowski07d23342015-03-17 09:04:14 -07004108 /* When running simultaneous discovery, the LE scanning time
4109 * should occupy the whole discovery time sine BR/EDR inquiry
4110 * and LE scanning are scheduled by the controller.
4111 *
4112 * For interleaving discovery in comparison, BR/EDR inquiry
4113 * and LE scanning are done sequentially with separate
4114 * timeouts.
4115 */
4116 if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks))
4117 timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
4118 else
4119 timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
Andre Guedes7c307722013-04-30 15:29:28 -03004120 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004121 case DISCOV_TYPE_BREDR:
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004122 timeout = 0;
Andre Guedes7c307722013-04-30 15:29:28 -03004123 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004124 default:
4125 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004126 timeout = 0;
4127 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004128 }
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004129
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004130 if (timeout) {
4131 /* When service discovery is used and the controller has
4132 * a strict duplicate filter, it is important to remember
4133 * the start and duration of the scan. This is required
4134 * for restarting scanning during the discovery phase.
4135 */
4136 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER,
4137 &hdev->quirks) &&
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004138 hdev->discovery.result_filtering) {
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004139 hdev->discovery.scan_start = jiffies;
4140 hdev->discovery.scan_duration = timeout;
4141 }
4142
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004143 queue_delayed_work(hdev->workqueue,
4144 &hdev->le_scan_disable, timeout);
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004145 }
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004146
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004147unlock:
4148 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03004149}
4150
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004151static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004152 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004153{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004154 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004155 struct mgmt_pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03004156 struct hci_request req;
Marcel Holtmann80190442014-12-04 11:36:36 +01004157 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04004158 int err;
4159
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004160 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004161
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004162 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004163
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004164 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004165 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4166 MGMT_STATUS_NOT_POWERED,
4167 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02004168 goto failed;
4169 }
4170
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004171 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004172 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004173 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4174 MGMT_STATUS_BUSY, &cp->type,
4175 sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03004176 goto failed;
4177 }
4178
Johan Hedberg2922a942014-12-05 13:36:06 +02004179 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004180 if (!cmd) {
4181 err = -ENOMEM;
4182 goto failed;
4183 }
4184
Johan Hedberg2922a942014-12-05 13:36:06 +02004185 cmd->cmd_complete = generic_cmd_complete;
4186
Marcel Holtmann22078802014-12-05 11:45:22 +01004187 /* Clear the discovery filter first to free any previously
4188 * allocated memory for the UUID list.
4189 */
4190 hci_discovery_filter_clear(hdev);
4191
Andre Guedes4aab14e2012-02-17 20:39:36 -03004192 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01004193 hdev->discovery.report_invalid_rssi = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03004194
Andre Guedes7c307722013-04-30 15:29:28 -03004195 hci_req_init(&req, hdev);
4196
Marcel Holtmann80190442014-12-04 11:36:36 +01004197 if (!trigger_discovery(&req, &status)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004198 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4199 status, &cp->type, sizeof(cp->type));
Johan Hedberg04106752013-01-10 14:54:09 +02004200 mgmt_pending_remove(cmd);
4201 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004202 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004203
Andre Guedes7c307722013-04-30 15:29:28 -03004204 err = hci_req_run(&req, start_discovery_complete);
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004205 if (err < 0) {
Johan Hedberg14a53662011-04-27 10:29:56 -04004206 mgmt_pending_remove(cmd);
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004207 goto failed;
4208 }
4209
4210 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04004211
4212failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004213 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004214 return err;
4215}
4216
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004217static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4218 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004219{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004220 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4221 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004222}
4223
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004224static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4225 void *data, u16 len)
4226{
4227 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004228 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004229 struct hci_request req;
4230 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4231 u16 uuid_count, expected_len;
4232 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004233 int err;
4234
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004235 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004236
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004237 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004238
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004239 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004240 err = mgmt_cmd_complete(sk, hdev->id,
4241 MGMT_OP_START_SERVICE_DISCOVERY,
4242 MGMT_STATUS_NOT_POWERED,
4243 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004244 goto failed;
4245 }
4246
4247 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004248 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004249 err = mgmt_cmd_complete(sk, hdev->id,
4250 MGMT_OP_START_SERVICE_DISCOVERY,
4251 MGMT_STATUS_BUSY, &cp->type,
4252 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004253 goto failed;
4254 }
4255
4256 uuid_count = __le16_to_cpu(cp->uuid_count);
4257 if (uuid_count > max_uuid_count) {
4258 BT_ERR("service_discovery: too big uuid_count value %u",
4259 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004260 err = mgmt_cmd_complete(sk, hdev->id,
4261 MGMT_OP_START_SERVICE_DISCOVERY,
4262 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4263 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004264 goto failed;
4265 }
4266
4267 expected_len = sizeof(*cp) + uuid_count * 16;
4268 if (expected_len != len) {
4269 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
4270 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004271 err = mgmt_cmd_complete(sk, hdev->id,
4272 MGMT_OP_START_SERVICE_DISCOVERY,
4273 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4274 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004275 goto failed;
4276 }
4277
4278 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02004279 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004280 if (!cmd) {
4281 err = -ENOMEM;
4282 goto failed;
4283 }
4284
Johan Hedberg2922a942014-12-05 13:36:06 +02004285 cmd->cmd_complete = service_discovery_cmd_complete;
4286
Marcel Holtmann22078802014-12-05 11:45:22 +01004287 /* Clear the discovery filter first to free any previously
4288 * allocated memory for the UUID list.
4289 */
4290 hci_discovery_filter_clear(hdev);
4291
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004292 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004293 hdev->discovery.type = cp->type;
4294 hdev->discovery.rssi = cp->rssi;
4295 hdev->discovery.uuid_count = uuid_count;
4296
4297 if (uuid_count > 0) {
4298 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4299 GFP_KERNEL);
4300 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004301 err = mgmt_cmd_complete(sk, hdev->id,
4302 MGMT_OP_START_SERVICE_DISCOVERY,
4303 MGMT_STATUS_FAILED,
4304 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004305 mgmt_pending_remove(cmd);
4306 goto failed;
4307 }
4308 }
4309
4310 hci_req_init(&req, hdev);
4311
4312 if (!trigger_discovery(&req, &status)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004313 err = mgmt_cmd_complete(sk, hdev->id,
4314 MGMT_OP_START_SERVICE_DISCOVERY,
4315 status, &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004316 mgmt_pending_remove(cmd);
4317 goto failed;
4318 }
4319
4320 err = hci_req_run(&req, start_discovery_complete);
4321 if (err < 0) {
4322 mgmt_pending_remove(cmd);
4323 goto failed;
4324 }
4325
4326 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
4327
4328failed:
4329 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004330 return err;
4331}
4332
Marcel Holtmann1904a852015-01-11 13:50:44 -08004333static void stop_discovery_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004334{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004335 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004336
Andre Guedes0e05bba2013-04-30 15:29:33 -03004337 BT_DBG("status %d", status);
4338
4339 hci_dev_lock(hdev);
4340
Johan Hedberg333ae952015-03-17 13:48:47 +02004341 cmd = pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004342 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004343 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004344 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004345 }
4346
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004347 if (!status)
4348 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004349
Andre Guedes0e05bba2013-04-30 15:29:33 -03004350 hci_dev_unlock(hdev);
4351}
4352
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004353static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004354 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004355{
Johan Hedbergd9306502012-02-20 23:25:18 +02004356 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004357 struct mgmt_pending_cmd *cmd;
Andre Guedes0e05bba2013-04-30 15:29:33 -03004358 struct hci_request req;
Johan Hedberg14a53662011-04-27 10:29:56 -04004359 int err;
4360
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004361 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004362
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004363 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004364
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004365 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004366 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4367 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4368 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004369 goto unlock;
4370 }
4371
4372 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004373 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4374 MGMT_STATUS_INVALID_PARAMS,
4375 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004376 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004377 }
4378
Johan Hedberg2922a942014-12-05 13:36:06 +02004379 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004380 if (!cmd) {
4381 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004382 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004383 }
4384
Johan Hedberg2922a942014-12-05 13:36:06 +02004385 cmd->cmd_complete = generic_cmd_complete;
4386
Andre Guedes0e05bba2013-04-30 15:29:33 -03004387 hci_req_init(&req, hdev);
4388
Johan Hedberg21a60d32014-06-10 14:05:58 +03004389 hci_stop_discovery(&req);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004390
Johan Hedberg21a60d32014-06-10 14:05:58 +03004391 err = hci_req_run(&req, stop_discovery_complete);
4392 if (!err) {
4393 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004394 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004395 }
4396
Johan Hedberg21a60d32014-06-10 14:05:58 +03004397 mgmt_pending_remove(cmd);
4398
4399 /* If no HCI commands were sent we're done */
4400 if (err == -ENODATA) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004401 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
4402 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg21a60d32014-06-10 14:05:58 +03004403 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
4404 }
Johan Hedberg14a53662011-04-27 10:29:56 -04004405
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004406unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004407 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004408 return err;
4409}
4410
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004411static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004412 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004413{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004414 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004415 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004416 int err;
4417
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004418 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004419
Johan Hedberg561aafb2012-01-04 13:31:59 +02004420 hci_dev_lock(hdev);
4421
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004422 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004423 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4424 MGMT_STATUS_FAILED, &cp->addr,
4425 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004426 goto failed;
4427 }
4428
Johan Hedberga198e7b2012-02-17 14:27:06 +02004429 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004430 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004431 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4432 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4433 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004434 goto failed;
4435 }
4436
4437 if (cp->name_known) {
4438 e->name_state = NAME_KNOWN;
4439 list_del(&e->list);
4440 } else {
4441 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02004442 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004443 }
4444
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004445 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4446 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004447
4448failed:
4449 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004450 return err;
4451}
4452
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004453static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004454 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004455{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004456 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004457 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004458 int err;
4459
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004460 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004461
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004462 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004463 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4464 MGMT_STATUS_INVALID_PARAMS,
4465 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004466
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004467 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004468
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004469 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4470 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004471 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004472 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004473 goto done;
4474 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004475
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004476 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4477 sk);
4478 status = MGMT_STATUS_SUCCESS;
4479
4480done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004481 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4482 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004483
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004484 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004485
4486 return err;
4487}
4488
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004489static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004490 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004491{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004492 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004493 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004494 int err;
4495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004496 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004497
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004498 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004499 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4500 MGMT_STATUS_INVALID_PARAMS,
4501 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004502
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004503 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004504
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004505 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4506 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004507 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004508 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004509 goto done;
4510 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004511
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004512 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4513 sk);
4514 status = MGMT_STATUS_SUCCESS;
4515
4516done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004517 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4518 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004519
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004520 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004521
4522 return err;
4523}
4524
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004525static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4526 u16 len)
4527{
4528 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004529 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004530 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004531 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004532
4533 BT_DBG("%s", hdev->name);
4534
Szymon Jancc72d4b82012-03-16 16:02:57 +01004535 source = __le16_to_cpu(cp->source);
4536
4537 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004538 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4539 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004540
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004541 hci_dev_lock(hdev);
4542
Szymon Jancc72d4b82012-03-16 16:02:57 +01004543 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004544 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4545 hdev->devid_product = __le16_to_cpu(cp->product);
4546 hdev->devid_version = __le16_to_cpu(cp->version);
4547
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004548 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4549 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004550
Johan Hedberg890ea892013-03-15 17:06:52 -05004551 hci_req_init(&req, hdev);
4552 update_eir(&req);
4553 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004554
4555 hci_dev_unlock(hdev);
4556
4557 return err;
4558}
4559
Marcel Holtmann1904a852015-01-11 13:50:44 -08004560static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4561 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004562{
4563 struct cmd_lookup match = { NULL, hdev };
4564
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304565 hci_dev_lock(hdev);
4566
Johan Hedberg4375f102013-09-25 13:26:10 +03004567 if (status) {
4568 u8 mgmt_err = mgmt_status(status);
4569
4570 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4571 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304572 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004573 }
4574
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004575 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004576 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004577 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004578 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004579
Johan Hedberg4375f102013-09-25 13:26:10 +03004580 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4581 &match);
4582
4583 new_settings(hdev, match.sk);
4584
4585 if (match.sk)
4586 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304587
4588unlock:
4589 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004590}
4591
Marcel Holtmann21b51872013-10-10 09:47:53 -07004592static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4593 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004594{
4595 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004596 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004597 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004598 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004599 int err;
4600
4601 BT_DBG("request for %s", hdev->name);
4602
Johan Hedberge6fe7982013-10-02 15:45:22 +03004603 status = mgmt_le_support(hdev);
4604 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004605 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4606 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004607
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004608 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004609 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4610 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004611
4612 hci_dev_lock(hdev);
4613
4614 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004615
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004616 /* The following conditions are ones which mean that we should
4617 * not do any HCI communication but directly send a mgmt
4618 * response to user space (after toggling the flag if
4619 * necessary).
4620 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004621 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004622 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4623 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004624 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004625 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004626 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004627 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004628
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004629 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004630 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004631 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004632 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004633 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004634 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004635 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004636 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004637 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004638 }
4639
4640 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4641 if (err < 0)
4642 goto unlock;
4643
4644 if (changed)
4645 err = new_settings(hdev, sk);
4646
4647 goto unlock;
4648 }
4649
Johan Hedberg333ae952015-03-17 13:48:47 +02004650 if (pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4651 pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004652 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4653 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004654 goto unlock;
4655 }
4656
4657 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4658 if (!cmd) {
4659 err = -ENOMEM;
4660 goto unlock;
4661 }
4662
4663 hci_req_init(&req, hdev);
4664
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004665 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004666 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004667 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004668 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004669
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004670 if (val)
4671 enable_advertising(&req);
4672 else
4673 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03004674
4675 err = hci_req_run(&req, set_advertising_complete);
4676 if (err < 0)
4677 mgmt_pending_remove(cmd);
4678
4679unlock:
4680 hci_dev_unlock(hdev);
4681 return err;
4682}
4683
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004684static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4685 void *data, u16 len)
4686{
4687 struct mgmt_cp_set_static_address *cp = data;
4688 int err;
4689
4690 BT_DBG("%s", hdev->name);
4691
Marcel Holtmann62af4442013-10-02 22:10:32 -07004692 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004693 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4694 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004695
4696 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004697 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4698 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004699
4700 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4701 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004702 return mgmt_cmd_status(sk, hdev->id,
4703 MGMT_OP_SET_STATIC_ADDRESS,
4704 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004705
4706 /* Two most significant bits shall be set */
4707 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004708 return mgmt_cmd_status(sk, hdev->id,
4709 MGMT_OP_SET_STATIC_ADDRESS,
4710 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004711 }
4712
4713 hci_dev_lock(hdev);
4714
4715 bacpy(&hdev->static_addr, &cp->bdaddr);
4716
Marcel Holtmann93690c22015-03-06 10:11:21 -08004717 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4718 if (err < 0)
4719 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004720
Marcel Holtmann93690c22015-03-06 10:11:21 -08004721 err = new_settings(hdev, sk);
4722
4723unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004724 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004725 return err;
4726}
4727
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004728static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4729 void *data, u16 len)
4730{
4731 struct mgmt_cp_set_scan_params *cp = data;
4732 __u16 interval, window;
4733 int err;
4734
4735 BT_DBG("%s", hdev->name);
4736
4737 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004738 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4739 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004740
4741 interval = __le16_to_cpu(cp->interval);
4742
4743 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004744 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4745 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004746
4747 window = __le16_to_cpu(cp->window);
4748
4749 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004750 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4751 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004752
Marcel Holtmann899e1072013-10-14 09:55:32 -07004753 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004754 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4755 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004756
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004757 hci_dev_lock(hdev);
4758
4759 hdev->le_scan_interval = interval;
4760 hdev->le_scan_window = window;
4761
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004762 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4763 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004764
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004765 /* If background scan is running, restart it so new parameters are
4766 * loaded.
4767 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004768 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004769 hdev->discovery.state == DISCOVERY_STOPPED) {
4770 struct hci_request req;
4771
4772 hci_req_init(&req, hdev);
4773
4774 hci_req_add_le_scan_disable(&req);
4775 hci_req_add_le_passive_scan(&req);
4776
4777 hci_req_run(&req, NULL);
4778 }
4779
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004780 hci_dev_unlock(hdev);
4781
4782 return err;
4783}
4784
Marcel Holtmann1904a852015-01-11 13:50:44 -08004785static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4786 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004787{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004788 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004789
4790 BT_DBG("status 0x%02x", status);
4791
4792 hci_dev_lock(hdev);
4793
Johan Hedberg333ae952015-03-17 13:48:47 +02004794 cmd = pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004795 if (!cmd)
4796 goto unlock;
4797
4798 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004799 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4800 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004801 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004802 struct mgmt_mode *cp = cmd->param;
4803
4804 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004805 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004806 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004807 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004808
Johan Hedberg33e38b32013-03-15 17:07:05 -05004809 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4810 new_settings(hdev, cmd->sk);
4811 }
4812
4813 mgmt_pending_remove(cmd);
4814
4815unlock:
4816 hci_dev_unlock(hdev);
4817}
4818
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004819static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004820 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004821{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004822 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004823 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004824 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004825 int err;
4826
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004827 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004828
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004829 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004830 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004831 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4832 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004833
Johan Hedberga7e80f22013-01-09 16:05:19 +02004834 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004835 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4836 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004837
Antti Julkuf6422ec2011-06-22 13:11:56 +03004838 hci_dev_lock(hdev);
4839
Johan Hedberg333ae952015-03-17 13:48:47 +02004840 if (pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004841 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4842 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004843 goto unlock;
4844 }
4845
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004846 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004847 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4848 hdev);
4849 goto unlock;
4850 }
4851
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004852 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004853 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004854 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4855 hdev);
4856 new_settings(hdev, sk);
4857 goto unlock;
4858 }
4859
Johan Hedberg33e38b32013-03-15 17:07:05 -05004860 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4861 data, len);
4862 if (!cmd) {
4863 err = -ENOMEM;
4864 goto unlock;
4865 }
4866
4867 hci_req_init(&req, hdev);
4868
Johan Hedberg406d7802013-03-15 17:07:09 -05004869 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004870
4871 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004872 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004873 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4874 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004875 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004876 }
4877
Johan Hedberg33e38b32013-03-15 17:07:05 -05004878unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004879 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004880
Antti Julkuf6422ec2011-06-22 13:11:56 +03004881 return err;
4882}
4883
Marcel Holtmann1904a852015-01-11 13:50:44 -08004884static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004885{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004886 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004887
4888 BT_DBG("status 0x%02x", status);
4889
4890 hci_dev_lock(hdev);
4891
Johan Hedberg333ae952015-03-17 13:48:47 +02004892 cmd = pending_find(MGMT_OP_SET_BREDR, hdev);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004893 if (!cmd)
4894 goto unlock;
4895
4896 if (status) {
4897 u8 mgmt_err = mgmt_status(status);
4898
4899 /* We need to restore the flag if related HCI commands
4900 * failed.
4901 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004902 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004903
Johan Hedberga69e8372015-03-06 21:08:53 +02004904 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004905 } else {
4906 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4907 new_settings(hdev, cmd->sk);
4908 }
4909
4910 mgmt_pending_remove(cmd);
4911
4912unlock:
4913 hci_dev_unlock(hdev);
4914}
4915
4916static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4917{
4918 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004919 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004920 struct hci_request req;
4921 int err;
4922
4923 BT_DBG("request for %s", hdev->name);
4924
4925 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004926 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4927 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004928
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004929 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004930 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4931 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004932
4933 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004934 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4935 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004936
4937 hci_dev_lock(hdev);
4938
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004939 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004940 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4941 goto unlock;
4942 }
4943
4944 if (!hdev_is_powered(hdev)) {
4945 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004946 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4947 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4948 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4949 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4950 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004951 }
4952
Marcel Holtmannce05d602015-03-13 02:11:03 -07004953 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004954
4955 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4956 if (err < 0)
4957 goto unlock;
4958
4959 err = new_settings(hdev, sk);
4960 goto unlock;
4961 }
4962
4963 /* Reject disabling when powered on */
4964 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004965 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4966 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004967 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004968 } else {
4969 /* When configuring a dual-mode controller to operate
4970 * with LE only and using a static address, then switching
4971 * BR/EDR back on is not allowed.
4972 *
4973 * Dual-mode controllers shall operate with the public
4974 * address as its identity address for BR/EDR and LE. So
4975 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004976 *
4977 * The same restrictions applies when secure connections
4978 * has been enabled. For BR/EDR this is a controller feature
4979 * while for LE it is a host stack feature. This means that
4980 * switching BR/EDR back on when secure connections has been
4981 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004982 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004983 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004984 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004985 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004986 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4987 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004988 goto unlock;
4989 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004990 }
4991
Johan Hedberg333ae952015-03-17 13:48:47 +02004992 if (pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004993 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4994 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004995 goto unlock;
4996 }
4997
4998 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4999 if (!cmd) {
5000 err = -ENOMEM;
5001 goto unlock;
5002 }
5003
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07005004 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03005005 * generates the correct flags.
5006 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005007 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03005008
5009 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005010
Johan Hedberg432df052014-08-01 11:13:31 +03005011 write_fast_connectable(&req, false);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02005012 __hci_update_page_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005013
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07005014 /* Since only the advertising data flags will change, there
5015 * is no need to update the scan response data.
5016 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07005017 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005018
Johan Hedberg0663ca22013-10-02 13:43:14 +03005019 err = hci_req_run(&req, set_bredr_complete);
5020 if (err < 0)
5021 mgmt_pending_remove(cmd);
5022
5023unlock:
5024 hci_dev_unlock(hdev);
5025 return err;
5026}
5027
Johan Hedberga1443f52015-01-23 15:42:46 +02005028static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
5029{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005030 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005031 struct mgmt_mode *cp;
5032
5033 BT_DBG("%s status %u", hdev->name, status);
5034
5035 hci_dev_lock(hdev);
5036
Johan Hedberg333ae952015-03-17 13:48:47 +02005037 cmd = pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
Johan Hedberga1443f52015-01-23 15:42:46 +02005038 if (!cmd)
5039 goto unlock;
5040
5041 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005042 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
5043 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02005044 goto remove;
5045 }
5046
5047 cp = cmd->param;
5048
5049 switch (cp->val) {
5050 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005051 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
5052 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005053 break;
5054 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005055 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005056 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005057 break;
5058 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005059 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
5060 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005061 break;
5062 }
5063
5064 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
5065 new_settings(hdev, cmd->sk);
5066
5067remove:
5068 mgmt_pending_remove(cmd);
5069unlock:
5070 hci_dev_unlock(hdev);
5071}
5072
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005073static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
5074 void *data, u16 len)
5075{
5076 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005077 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005078 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03005079 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005080 int err;
5081
5082 BT_DBG("request for %s", hdev->name);
5083
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005084 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005085 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005086 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5087 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005088
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005089 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02005090 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005091 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005092 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5093 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08005094
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005095 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005096 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005097 MGMT_STATUS_INVALID_PARAMS);
5098
5099 hci_dev_lock(hdev);
5100
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005101 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005102 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005103 bool changed;
5104
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005105 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005106 changed = !hci_dev_test_and_set_flag(hdev,
5107 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005108 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005109 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005110 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005111 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005112 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005113 changed = hci_dev_test_and_clear_flag(hdev,
5114 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005115 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005116 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005117
5118 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5119 if (err < 0)
5120 goto failed;
5121
5122 if (changed)
5123 err = new_settings(hdev, sk);
5124
5125 goto failed;
5126 }
5127
Johan Hedberg333ae952015-03-17 13:48:47 +02005128 if (pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005129 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5130 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005131 goto failed;
5132 }
5133
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005134 val = !!cp->val;
5135
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005136 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5137 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005138 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5139 goto failed;
5140 }
5141
5142 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
5143 if (!cmd) {
5144 err = -ENOMEM;
5145 goto failed;
5146 }
5147
Johan Hedberga1443f52015-01-23 15:42:46 +02005148 hci_req_init(&req, hdev);
5149 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
5150 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005151 if (err < 0) {
5152 mgmt_pending_remove(cmd);
5153 goto failed;
5154 }
5155
5156failed:
5157 hci_dev_unlock(hdev);
5158 return err;
5159}
5160
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005161static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
5162 void *data, u16 len)
5163{
5164 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03005165 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005166 int err;
5167
5168 BT_DBG("request for %s", hdev->name);
5169
Johan Hedbergb97109792014-06-24 14:00:28 +03005170 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005171 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
5172 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005173
5174 hci_dev_lock(hdev);
5175
5176 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07005177 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005178 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005179 changed = hci_dev_test_and_clear_flag(hdev,
5180 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005181
Johan Hedbergb97109792014-06-24 14:00:28 +03005182 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07005183 use_changed = !hci_dev_test_and_set_flag(hdev,
5184 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005185 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005186 use_changed = hci_dev_test_and_clear_flag(hdev,
5187 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005188
5189 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005190 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03005191 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
5192 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
5193 sizeof(mode), &mode);
5194 }
5195
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005196 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
5197 if (err < 0)
5198 goto unlock;
5199
5200 if (changed)
5201 err = new_settings(hdev, sk);
5202
5203unlock:
5204 hci_dev_unlock(hdev);
5205 return err;
5206}
5207
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005208static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5209 u16 len)
5210{
5211 struct mgmt_cp_set_privacy *cp = cp_data;
5212 bool changed;
5213 int err;
5214
5215 BT_DBG("request for %s", hdev->name);
5216
5217 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005218 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5219 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005220
5221 if (cp->privacy != 0x00 && cp->privacy != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005222 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5223 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005224
5225 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005226 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5227 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005228
5229 hci_dev_lock(hdev);
5230
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005231 /* If user space supports this command it is also expected to
5232 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
5233 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005234 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005235
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005236 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005237 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005238 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005239 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005240 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005241 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005242 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005243 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005244 }
5245
5246 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
5247 if (err < 0)
5248 goto unlock;
5249
5250 if (changed)
5251 err = new_settings(hdev, sk);
5252
5253unlock:
5254 hci_dev_unlock(hdev);
5255 return err;
5256}
5257
Johan Hedberg41edf162014-02-18 10:19:35 +02005258static bool irk_is_valid(struct mgmt_irk_info *irk)
5259{
5260 switch (irk->addr.type) {
5261 case BDADDR_LE_PUBLIC:
5262 return true;
5263
5264 case BDADDR_LE_RANDOM:
5265 /* Two most significant bits shall be set */
5266 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5267 return false;
5268 return true;
5269 }
5270
5271 return false;
5272}
5273
5274static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5275 u16 len)
5276{
5277 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005278 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5279 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005280 u16 irk_count, expected_len;
5281 int i, err;
5282
5283 BT_DBG("request for %s", hdev->name);
5284
5285 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005286 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5287 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005288
5289 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005290 if (irk_count > max_irk_count) {
5291 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005292 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5293 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005294 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005295
5296 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
5297 if (expected_len != len) {
5298 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02005299 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005300 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5301 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005302 }
5303
5304 BT_DBG("%s irk_count %u", hdev->name, irk_count);
5305
5306 for (i = 0; i < irk_count; i++) {
5307 struct mgmt_irk_info *key = &cp->irks[i];
5308
5309 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005310 return mgmt_cmd_status(sk, hdev->id,
5311 MGMT_OP_LOAD_IRKS,
5312 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005313 }
5314
5315 hci_dev_lock(hdev);
5316
5317 hci_smp_irks_clear(hdev);
5318
5319 for (i = 0; i < irk_count; i++) {
5320 struct mgmt_irk_info *irk = &cp->irks[i];
5321 u8 addr_type;
5322
5323 if (irk->addr.type == BDADDR_LE_PUBLIC)
5324 addr_type = ADDR_LE_DEV_PUBLIC;
5325 else
5326 addr_type = ADDR_LE_DEV_RANDOM;
5327
5328 hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
5329 BDADDR_ANY);
5330 }
5331
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005332 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005333
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005334 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005335
5336 hci_dev_unlock(hdev);
5337
5338 return err;
5339}
5340
Johan Hedberg3f706b72013-01-20 14:27:16 +02005341static bool ltk_is_valid(struct mgmt_ltk_info *key)
5342{
5343 if (key->master != 0x00 && key->master != 0x01)
5344 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005345
5346 switch (key->addr.type) {
5347 case BDADDR_LE_PUBLIC:
5348 return true;
5349
5350 case BDADDR_LE_RANDOM:
5351 /* Two most significant bits shall be set */
5352 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5353 return false;
5354 return true;
5355 }
5356
5357 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005358}
5359
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005360static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005361 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005362{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005363 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005364 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5365 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005366 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005367 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005368
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005369 BT_DBG("request for %s", hdev->name);
5370
5371 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005372 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5373 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005374
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005375 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005376 if (key_count > max_key_count) {
5377 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005378 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5379 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005380 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005381
5382 expected_len = sizeof(*cp) + key_count *
5383 sizeof(struct mgmt_ltk_info);
5384 if (expected_len != len) {
5385 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02005386 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005387 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5388 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005389 }
5390
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005391 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005392
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005393 for (i = 0; i < key_count; i++) {
5394 struct mgmt_ltk_info *key = &cp->keys[i];
5395
Johan Hedberg3f706b72013-01-20 14:27:16 +02005396 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005397 return mgmt_cmd_status(sk, hdev->id,
5398 MGMT_OP_LOAD_LONG_TERM_KEYS,
5399 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005400 }
5401
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005402 hci_dev_lock(hdev);
5403
5404 hci_smp_ltks_clear(hdev);
5405
5406 for (i = 0; i < key_count; i++) {
5407 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedbergd7b25452014-05-23 13:19:53 +03005408 u8 type, addr_type, authenticated;
Marcel Holtmann79d95a12013-10-13 03:57:38 -07005409
5410 if (key->addr.type == BDADDR_LE_PUBLIC)
5411 addr_type = ADDR_LE_DEV_PUBLIC;
5412 else
5413 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005414
Johan Hedberg61b43352014-05-29 19:36:53 +03005415 switch (key->type) {
5416 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005417 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005418 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005419 break;
5420 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005421 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005422 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005423 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005424 case MGMT_LTK_P256_UNAUTH:
5425 authenticated = 0x00;
5426 type = SMP_LTK_P256;
5427 break;
5428 case MGMT_LTK_P256_AUTH:
5429 authenticated = 0x01;
5430 type = SMP_LTK_P256;
5431 break;
5432 case MGMT_LTK_P256_DEBUG:
5433 authenticated = 0x00;
5434 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03005435 default:
5436 continue;
5437 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005438
Johan Hedberg35d70272014-02-19 14:57:47 +02005439 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type,
Johan Hedbergd7b25452014-05-23 13:19:53 +03005440 authenticated, key->val, key->enc_size, key->ediv,
Johan Hedberg35d70272014-02-19 14:57:47 +02005441 key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005442 }
5443
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005444 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005445 NULL, 0);
5446
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005447 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005448
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005449 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005450}
5451
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005452static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005453{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005454 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005455 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005456 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005457
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005458 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005459
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005460 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005461 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005462 rp.tx_power = conn->tx_power;
5463 rp.max_tx_power = conn->max_tx_power;
5464 } else {
5465 rp.rssi = HCI_RSSI_INVALID;
5466 rp.tx_power = HCI_TX_POWER_INVALID;
5467 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005468 }
5469
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005470 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5471 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005472
5473 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005474 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005475
5476 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005477}
5478
Marcel Holtmann1904a852015-01-11 13:50:44 -08005479static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5480 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005481{
5482 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005483 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005484 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005485 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005486 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005487
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005488 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005489
5490 hci_dev_lock(hdev);
5491
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005492 /* Commands sent in request are either Read RSSI or Read Transmit Power
5493 * Level so we check which one was last sent to retrieve connection
5494 * handle. Both commands have handle as first parameter so it's safe to
5495 * cast data on the same command struct.
5496 *
5497 * First command sent is always Read RSSI and we fail only if it fails.
5498 * In other case we simply override error to indicate success as we
5499 * already remembered if TX power value is actually valid.
5500 */
5501 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5502 if (!cp) {
5503 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005504 status = MGMT_STATUS_SUCCESS;
5505 } else {
5506 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005507 }
5508
5509 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005510 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005511 goto unlock;
5512 }
5513
5514 handle = __le16_to_cpu(cp->handle);
5515 conn = hci_conn_hash_lookup_handle(hdev, handle);
5516 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005517 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005518 goto unlock;
5519 }
5520
Johan Hedberg333ae952015-03-17 13:48:47 +02005521 cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005522 if (!cmd)
5523 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005524
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005525 cmd->cmd_complete(cmd, status);
5526 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005527
5528unlock:
5529 hci_dev_unlock(hdev);
5530}
5531
5532static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5533 u16 len)
5534{
5535 struct mgmt_cp_get_conn_info *cp = data;
5536 struct mgmt_rp_get_conn_info rp;
5537 struct hci_conn *conn;
5538 unsigned long conn_info_age;
5539 int err = 0;
5540
5541 BT_DBG("%s", hdev->name);
5542
5543 memset(&rp, 0, sizeof(rp));
5544 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5545 rp.addr.type = cp->addr.type;
5546
5547 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005548 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5549 MGMT_STATUS_INVALID_PARAMS,
5550 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005551
5552 hci_dev_lock(hdev);
5553
5554 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005555 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5556 MGMT_STATUS_NOT_POWERED, &rp,
5557 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005558 goto unlock;
5559 }
5560
5561 if (cp->addr.type == BDADDR_BREDR)
5562 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5563 &cp->addr.bdaddr);
5564 else
5565 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5566
5567 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005568 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5569 MGMT_STATUS_NOT_CONNECTED, &rp,
5570 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005571 goto unlock;
5572 }
5573
Johan Hedberg333ae952015-03-17 13:48:47 +02005574 if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005575 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5576 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005577 goto unlock;
5578 }
5579
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005580 /* To avoid client trying to guess when to poll again for information we
5581 * calculate conn info age as random value between min/max set in hdev.
5582 */
5583 conn_info_age = hdev->conn_info_min_age +
5584 prandom_u32_max(hdev->conn_info_max_age -
5585 hdev->conn_info_min_age);
5586
5587 /* Query controller to refresh cached values if they are too old or were
5588 * never read.
5589 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005590 if (time_after(jiffies, conn->conn_info_timestamp +
5591 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005592 !conn->conn_info_timestamp) {
5593 struct hci_request req;
5594 struct hci_cp_read_tx_power req_txp_cp;
5595 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005596 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005597
5598 hci_req_init(&req, hdev);
5599 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5600 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5601 &req_rssi_cp);
5602
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005603 /* For LE links TX power does not change thus we don't need to
5604 * query for it once value is known.
5605 */
5606 if (!bdaddr_type_is_le(cp->addr.type) ||
5607 conn->tx_power == HCI_TX_POWER_INVALID) {
5608 req_txp_cp.handle = cpu_to_le16(conn->handle);
5609 req_txp_cp.type = 0x00;
5610 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5611 sizeof(req_txp_cp), &req_txp_cp);
5612 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005613
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005614 /* Max TX power needs to be read only once per connection */
5615 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5616 req_txp_cp.handle = cpu_to_le16(conn->handle);
5617 req_txp_cp.type = 0x01;
5618 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5619 sizeof(req_txp_cp), &req_txp_cp);
5620 }
5621
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005622 err = hci_req_run(&req, conn_info_refresh_complete);
5623 if (err < 0)
5624 goto unlock;
5625
5626 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5627 data, len);
5628 if (!cmd) {
5629 err = -ENOMEM;
5630 goto unlock;
5631 }
5632
5633 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005634 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005635 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005636
5637 conn->conn_info_timestamp = jiffies;
5638 } else {
5639 /* Cache is valid, just reply with values cached in hci_conn */
5640 rp.rssi = conn->rssi;
5641 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005642 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005643
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005644 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5645 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005646 }
5647
5648unlock:
5649 hci_dev_unlock(hdev);
5650 return err;
5651}
5652
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005653static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005654{
5655 struct hci_conn *conn = cmd->user_data;
5656 struct mgmt_rp_get_clock_info rp;
5657 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005658 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005659
5660 memset(&rp, 0, sizeof(rp));
5661 memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
5662
5663 if (status)
5664 goto complete;
5665
5666 hdev = hci_dev_get(cmd->index);
5667 if (hdev) {
5668 rp.local_clock = cpu_to_le32(hdev->clock);
5669 hci_dev_put(hdev);
5670 }
5671
5672 if (conn) {
5673 rp.piconet_clock = cpu_to_le32(conn->clock);
5674 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5675 }
5676
5677complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005678 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5679 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005680
5681 if (conn) {
5682 hci_conn_drop(conn);
5683 hci_conn_put(conn);
5684 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005685
5686 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005687}
5688
Marcel Holtmann1904a852015-01-11 13:50:44 -08005689static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005690{
Johan Hedberg95868422014-06-28 17:54:07 +03005691 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005692 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005693 struct hci_conn *conn;
5694
5695 BT_DBG("%s status %u", hdev->name, status);
5696
5697 hci_dev_lock(hdev);
5698
5699 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5700 if (!hci_cp)
5701 goto unlock;
5702
5703 if (hci_cp->which) {
5704 u16 handle = __le16_to_cpu(hci_cp->handle);
5705 conn = hci_conn_hash_lookup_handle(hdev, handle);
5706 } else {
5707 conn = NULL;
5708 }
5709
Johan Hedberg333ae952015-03-17 13:48:47 +02005710 cmd = pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005711 if (!cmd)
5712 goto unlock;
5713
Johan Hedberg69487372014-12-05 13:36:07 +02005714 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005715 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005716
5717unlock:
5718 hci_dev_unlock(hdev);
5719}
5720
5721static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5722 u16 len)
5723{
5724 struct mgmt_cp_get_clock_info *cp = data;
5725 struct mgmt_rp_get_clock_info rp;
5726 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005727 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005728 struct hci_request req;
5729 struct hci_conn *conn;
5730 int err;
5731
5732 BT_DBG("%s", hdev->name);
5733
5734 memset(&rp, 0, sizeof(rp));
5735 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5736 rp.addr.type = cp->addr.type;
5737
5738 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005739 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5740 MGMT_STATUS_INVALID_PARAMS,
5741 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005742
5743 hci_dev_lock(hdev);
5744
5745 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005746 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5747 MGMT_STATUS_NOT_POWERED, &rp,
5748 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005749 goto unlock;
5750 }
5751
5752 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5753 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5754 &cp->addr.bdaddr);
5755 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005756 err = mgmt_cmd_complete(sk, hdev->id,
5757 MGMT_OP_GET_CLOCK_INFO,
5758 MGMT_STATUS_NOT_CONNECTED,
5759 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005760 goto unlock;
5761 }
5762 } else {
5763 conn = NULL;
5764 }
5765
5766 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5767 if (!cmd) {
5768 err = -ENOMEM;
5769 goto unlock;
5770 }
5771
Johan Hedberg69487372014-12-05 13:36:07 +02005772 cmd->cmd_complete = clock_info_cmd_complete;
5773
Johan Hedberg95868422014-06-28 17:54:07 +03005774 hci_req_init(&req, hdev);
5775
5776 memset(&hci_cp, 0, sizeof(hci_cp));
5777 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5778
5779 if (conn) {
5780 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005781 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005782
5783 hci_cp.handle = cpu_to_le16(conn->handle);
5784 hci_cp.which = 0x01; /* Piconet clock */
5785 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5786 }
5787
5788 err = hci_req_run(&req, get_clock_info_complete);
5789 if (err < 0)
5790 mgmt_pending_remove(cmd);
5791
5792unlock:
5793 hci_dev_unlock(hdev);
5794 return err;
5795}
5796
Johan Hedberg5a154e62014-12-19 22:26:02 +02005797static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5798{
5799 struct hci_conn *conn;
5800
5801 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5802 if (!conn)
5803 return false;
5804
5805 if (conn->dst_type != type)
5806 return false;
5807
5808 if (conn->state != BT_CONNECTED)
5809 return false;
5810
5811 return true;
5812}
5813
5814/* This function requires the caller holds hdev->lock */
5815static int hci_conn_params_set(struct hci_request *req, bdaddr_t *addr,
5816 u8 addr_type, u8 auto_connect)
5817{
5818 struct hci_dev *hdev = req->hdev;
5819 struct hci_conn_params *params;
5820
5821 params = hci_conn_params_add(hdev, addr, addr_type);
5822 if (!params)
5823 return -EIO;
5824
5825 if (params->auto_connect == auto_connect)
5826 return 0;
5827
5828 list_del_init(&params->action);
5829
5830 switch (auto_connect) {
5831 case HCI_AUTO_CONN_DISABLED:
5832 case HCI_AUTO_CONN_LINK_LOSS:
5833 __hci_update_background_scan(req);
5834 break;
5835 case HCI_AUTO_CONN_REPORT:
5836 list_add(&params->action, &hdev->pend_le_reports);
5837 __hci_update_background_scan(req);
5838 break;
5839 case HCI_AUTO_CONN_DIRECT:
5840 case HCI_AUTO_CONN_ALWAYS:
5841 if (!is_connected(hdev, addr, addr_type)) {
5842 list_add(&params->action, &hdev->pend_le_conns);
5843 __hci_update_background_scan(req);
5844 }
5845 break;
5846 }
5847
5848 params->auto_connect = auto_connect;
5849
5850 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5851 auto_connect);
5852
5853 return 0;
5854}
5855
Marcel Holtmann8afef092014-06-29 22:28:34 +02005856static void device_added(struct sock *sk, struct hci_dev *hdev,
5857 bdaddr_t *bdaddr, u8 type, u8 action)
5858{
5859 struct mgmt_ev_device_added ev;
5860
5861 bacpy(&ev.addr.bdaddr, bdaddr);
5862 ev.addr.type = type;
5863 ev.action = action;
5864
5865 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5866}
5867
Marcel Holtmann1904a852015-01-11 13:50:44 -08005868static void add_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg5a154e62014-12-19 22:26:02 +02005869{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005870 struct mgmt_pending_cmd *cmd;
Johan Hedberg5a154e62014-12-19 22:26:02 +02005871
5872 BT_DBG("status 0x%02x", status);
5873
5874 hci_dev_lock(hdev);
5875
Johan Hedberg333ae952015-03-17 13:48:47 +02005876 cmd = pending_find(MGMT_OP_ADD_DEVICE, hdev);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005877 if (!cmd)
5878 goto unlock;
5879
5880 cmd->cmd_complete(cmd, mgmt_status(status));
5881 mgmt_pending_remove(cmd);
5882
5883unlock:
5884 hci_dev_unlock(hdev);
5885}
5886
Marcel Holtmann2faade52014-06-29 19:44:03 +02005887static int add_device(struct sock *sk, struct hci_dev *hdev,
5888 void *data, u16 len)
5889{
5890 struct mgmt_cp_add_device *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005891 struct mgmt_pending_cmd *cmd;
Johan Hedberg5a154e62014-12-19 22:26:02 +02005892 struct hci_request req;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005893 u8 auto_conn, addr_type;
5894 int err;
5895
5896 BT_DBG("%s", hdev->name);
5897
Johan Hedberg66593582014-07-09 12:59:14 +03005898 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005899 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005900 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5901 MGMT_STATUS_INVALID_PARAMS,
5902 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005903
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005904 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005905 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5906 MGMT_STATUS_INVALID_PARAMS,
5907 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005908
Johan Hedberg5a154e62014-12-19 22:26:02 +02005909 hci_req_init(&req, hdev);
5910
Marcel Holtmann2faade52014-06-29 19:44:03 +02005911 hci_dev_lock(hdev);
5912
Johan Hedberg5a154e62014-12-19 22:26:02 +02005913 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_DEVICE, hdev, data, len);
5914 if (!cmd) {
5915 err = -ENOMEM;
5916 goto unlock;
5917 }
5918
5919 cmd->cmd_complete = addr_cmd_complete;
5920
Johan Hedberg66593582014-07-09 12:59:14 +03005921 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005922 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005923 if (cp->action != 0x01) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005924 err = cmd->cmd_complete(cmd,
5925 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005926 mgmt_pending_remove(cmd);
Johan Hedberg66593582014-07-09 12:59:14 +03005927 goto unlock;
5928 }
5929
5930 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5931 cp->addr.type);
5932 if (err)
5933 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005934
Johan Hedberg5a154e62014-12-19 22:26:02 +02005935 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03005936
Johan Hedberg66593582014-07-09 12:59:14 +03005937 goto added;
5938 }
5939
Marcel Holtmann2faade52014-06-29 19:44:03 +02005940 if (cp->addr.type == BDADDR_LE_PUBLIC)
5941 addr_type = ADDR_LE_DEV_PUBLIC;
5942 else
5943 addr_type = ADDR_LE_DEV_RANDOM;
5944
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005945 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005946 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005947 else if (cp->action == 0x01)
5948 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005949 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005950 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005951
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005952 /* If the connection parameters don't exist for this device,
5953 * they will be created and configured with defaults.
5954 */
Johan Hedberg5a154e62014-12-19 22:26:02 +02005955 if (hci_conn_params_set(&req, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005956 auto_conn) < 0) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005957 err = cmd->cmd_complete(cmd, MGMT_STATUS_FAILED);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005958 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005959 goto unlock;
5960 }
5961
Johan Hedberg66593582014-07-09 12:59:14 +03005962added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005963 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5964
Johan Hedberg5a154e62014-12-19 22:26:02 +02005965 err = hci_req_run(&req, add_device_complete);
5966 if (err < 0) {
5967 /* ENODATA means no HCI commands were needed (e.g. if
5968 * the adapter is powered off).
5969 */
Johan Hedberg9df74652014-12-19 22:26:03 +02005970 if (err == -ENODATA)
5971 err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005972 mgmt_pending_remove(cmd);
5973 }
Marcel Holtmann2faade52014-06-29 19:44:03 +02005974
5975unlock:
5976 hci_dev_unlock(hdev);
5977 return err;
5978}
5979
Marcel Holtmann8afef092014-06-29 22:28:34 +02005980static void device_removed(struct sock *sk, struct hci_dev *hdev,
5981 bdaddr_t *bdaddr, u8 type)
5982{
5983 struct mgmt_ev_device_removed ev;
5984
5985 bacpy(&ev.addr.bdaddr, bdaddr);
5986 ev.addr.type = type;
5987
5988 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5989}
5990
Marcel Holtmann1904a852015-01-11 13:50:44 -08005991static void remove_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005992{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005993 struct mgmt_pending_cmd *cmd;
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005994
5995 BT_DBG("status 0x%02x", status);
5996
5997 hci_dev_lock(hdev);
5998
Johan Hedberg333ae952015-03-17 13:48:47 +02005999 cmd = pending_find(MGMT_OP_REMOVE_DEVICE, hdev);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006000 if (!cmd)
6001 goto unlock;
6002
6003 cmd->cmd_complete(cmd, mgmt_status(status));
6004 mgmt_pending_remove(cmd);
6005
6006unlock:
6007 hci_dev_unlock(hdev);
6008}
6009
Marcel Holtmann2faade52014-06-29 19:44:03 +02006010static int remove_device(struct sock *sk, struct hci_dev *hdev,
6011 void *data, u16 len)
6012{
6013 struct mgmt_cp_remove_device *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006014 struct mgmt_pending_cmd *cmd;
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006015 struct hci_request req;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006016 int err;
6017
6018 BT_DBG("%s", hdev->name);
6019
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006020 hci_req_init(&req, hdev);
6021
Marcel Holtmann2faade52014-06-29 19:44:03 +02006022 hci_dev_lock(hdev);
6023
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006024 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_DEVICE, hdev, data, len);
6025 if (!cmd) {
6026 err = -ENOMEM;
6027 goto unlock;
6028 }
6029
6030 cmd->cmd_complete = addr_cmd_complete;
6031
Marcel Holtmann2faade52014-06-29 19:44:03 +02006032 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03006033 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006034 u8 addr_type;
6035
Johan Hedberg66593582014-07-09 12:59:14 +03006036 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006037 err = cmd->cmd_complete(cmd,
6038 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006039 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006040 goto unlock;
6041 }
6042
Johan Hedberg66593582014-07-09 12:59:14 +03006043 if (cp->addr.type == BDADDR_BREDR) {
6044 err = hci_bdaddr_list_del(&hdev->whitelist,
6045 &cp->addr.bdaddr,
6046 cp->addr.type);
6047 if (err) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006048 err = cmd->cmd_complete(cmd,
6049 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006050 mgmt_pending_remove(cmd);
Johan Hedberg66593582014-07-09 12:59:14 +03006051 goto unlock;
6052 }
6053
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006054 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03006055
Johan Hedberg66593582014-07-09 12:59:14 +03006056 device_removed(sk, hdev, &cp->addr.bdaddr,
6057 cp->addr.type);
6058 goto complete;
6059 }
6060
Marcel Holtmann2faade52014-06-29 19:44:03 +02006061 if (cp->addr.type == BDADDR_LE_PUBLIC)
6062 addr_type = ADDR_LE_DEV_PUBLIC;
6063 else
6064 addr_type = ADDR_LE_DEV_RANDOM;
6065
Johan Hedbergc71593d2014-07-02 17:37:28 +03006066 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6067 addr_type);
6068 if (!params) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006069 err = cmd->cmd_complete(cmd,
6070 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006071 mgmt_pending_remove(cmd);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006072 goto unlock;
6073 }
6074
6075 if (params->auto_connect == HCI_AUTO_CONN_DISABLED) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006076 err = cmd->cmd_complete(cmd,
6077 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006078 mgmt_pending_remove(cmd);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006079 goto unlock;
6080 }
6081
Johan Hedbergd1dbf122014-07-04 16:17:23 +03006082 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006083 list_del(&params->list);
6084 kfree(params);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006085 __hci_update_background_scan(&req);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006086
6087 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006088 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03006089 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03006090 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03006091
Marcel Holtmann2faade52014-06-29 19:44:03 +02006092 if (cp->addr.type) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006093 err = cmd->cmd_complete(cmd,
6094 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006095 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006096 goto unlock;
6097 }
6098
Johan Hedberg66593582014-07-09 12:59:14 +03006099 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
6100 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
6101 list_del(&b->list);
6102 kfree(b);
6103 }
6104
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006105 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03006106
Johan Hedberg19de0822014-07-06 13:06:51 +03006107 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
6108 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
6109 continue;
6110 device_removed(sk, hdev, &p->addr, p->addr_type);
6111 list_del(&p->action);
6112 list_del(&p->list);
6113 kfree(p);
6114 }
6115
6116 BT_DBG("All LE connection parameters were removed");
6117
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006118 __hci_update_background_scan(&req);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006119 }
6120
Johan Hedberg66593582014-07-09 12:59:14 +03006121complete:
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006122 err = hci_req_run(&req, remove_device_complete);
6123 if (err < 0) {
6124 /* ENODATA means no HCI commands were needed (e.g. if
6125 * the adapter is powered off).
6126 */
Johan Hedberg9df74652014-12-19 22:26:03 +02006127 if (err == -ENODATA)
6128 err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006129 mgmt_pending_remove(cmd);
6130 }
Marcel Holtmann2faade52014-06-29 19:44:03 +02006131
6132unlock:
6133 hci_dev_unlock(hdev);
6134 return err;
6135}
6136
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006137static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
6138 u16 len)
6139{
6140 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006141 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
6142 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006143 u16 param_count, expected_len;
6144 int i;
6145
6146 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006147 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6148 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006149
6150 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006151 if (param_count > max_param_count) {
6152 BT_ERR("load_conn_param: too big param_count value %u",
6153 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006154 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6155 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006156 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006157
6158 expected_len = sizeof(*cp) + param_count *
6159 sizeof(struct mgmt_conn_param);
6160 if (expected_len != len) {
6161 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
6162 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006163 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6164 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006165 }
6166
6167 BT_DBG("%s param_count %u", hdev->name, param_count);
6168
6169 hci_dev_lock(hdev);
6170
6171 hci_conn_params_clear_disabled(hdev);
6172
6173 for (i = 0; i < param_count; i++) {
6174 struct mgmt_conn_param *param = &cp->params[i];
6175 struct hci_conn_params *hci_param;
6176 u16 min, max, latency, timeout;
6177 u8 addr_type;
6178
6179 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
6180 param->addr.type);
6181
6182 if (param->addr.type == BDADDR_LE_PUBLIC) {
6183 addr_type = ADDR_LE_DEV_PUBLIC;
6184 } else if (param->addr.type == BDADDR_LE_RANDOM) {
6185 addr_type = ADDR_LE_DEV_RANDOM;
6186 } else {
6187 BT_ERR("Ignoring invalid connection parameters");
6188 continue;
6189 }
6190
6191 min = le16_to_cpu(param->min_interval);
6192 max = le16_to_cpu(param->max_interval);
6193 latency = le16_to_cpu(param->latency);
6194 timeout = le16_to_cpu(param->timeout);
6195
6196 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6197 min, max, latency, timeout);
6198
6199 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
6200 BT_ERR("Ignoring invalid connection parameters");
6201 continue;
6202 }
6203
6204 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
6205 addr_type);
6206 if (!hci_param) {
6207 BT_ERR("Failed to add connection parameters");
6208 continue;
6209 }
6210
6211 hci_param->conn_min_interval = min;
6212 hci_param->conn_max_interval = max;
6213 hci_param->conn_latency = latency;
6214 hci_param->supervision_timeout = timeout;
6215 }
6216
6217 hci_dev_unlock(hdev);
6218
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006219 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
6220 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006221}
6222
Marcel Holtmanndbece372014-07-04 18:11:55 +02006223static int set_external_config(struct sock *sk, struct hci_dev *hdev,
6224 void *data, u16 len)
6225{
6226 struct mgmt_cp_set_external_config *cp = data;
6227 bool changed;
6228 int err;
6229
6230 BT_DBG("%s", hdev->name);
6231
6232 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006233 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6234 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006235
6236 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006237 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6238 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006239
6240 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02006241 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6242 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006243
6244 hci_dev_lock(hdev);
6245
6246 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07006247 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006248 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006249 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006250
6251 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
6252 if (err < 0)
6253 goto unlock;
6254
6255 if (!changed)
6256 goto unlock;
6257
Marcel Holtmannf4537c02014-07-04 19:06:23 +02006258 err = new_options(hdev, sk);
6259
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006260 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02006261 mgmt_index_removed(hdev);
Marcel Holtmannd603b762014-07-06 12:11:14 +02006262
Marcel Holtmann516018a2015-03-13 02:11:04 -07006263 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006264 hci_dev_set_flag(hdev, HCI_CONFIG);
6265 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b762014-07-06 12:11:14 +02006266
6267 queue_work(hdev->req_workqueue, &hdev->power_on);
6268 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02006269 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b762014-07-06 12:11:14 +02006270 mgmt_index_added(hdev);
6271 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02006272 }
6273
6274unlock:
6275 hci_dev_unlock(hdev);
6276 return err;
6277}
6278
Marcel Holtmann9713c172014-07-06 12:11:15 +02006279static int set_public_address(struct sock *sk, struct hci_dev *hdev,
6280 void *data, u16 len)
6281{
6282 struct mgmt_cp_set_public_address *cp = data;
6283 bool changed;
6284 int err;
6285
6286 BT_DBG("%s", hdev->name);
6287
6288 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006289 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6290 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006291
6292 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02006293 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6294 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006295
6296 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02006297 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6298 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006299
6300 hci_dev_lock(hdev);
6301
6302 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
6303 bacpy(&hdev->public_addr, &cp->bdaddr);
6304
6305 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
6306 if (err < 0)
6307 goto unlock;
6308
6309 if (!changed)
6310 goto unlock;
6311
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006312 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006313 err = new_options(hdev, sk);
6314
6315 if (is_configured(hdev)) {
6316 mgmt_index_removed(hdev);
6317
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006318 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006319
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006320 hci_dev_set_flag(hdev, HCI_CONFIG);
6321 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006322
6323 queue_work(hdev->req_workqueue, &hdev->power_on);
6324 }
6325
6326unlock:
6327 hci_dev_unlock(hdev);
6328 return err;
6329}
6330
Marcel Holtmannbea41602015-03-14 22:43:17 -07006331static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
6332 u8 data_len)
6333{
6334 eir[eir_len++] = sizeof(type) + data_len;
6335 eir[eir_len++] = type;
6336 memcpy(&eir[eir_len], data, data_len);
6337 eir_len += data_len;
6338
6339 return eir_len;
6340}
6341
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006342static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
6343 void *data, u16 data_len)
6344{
6345 struct mgmt_cp_read_local_oob_ext_data *cp = data;
6346 struct mgmt_rp_read_local_oob_ext_data *rp;
6347 size_t rp_len;
6348 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006349 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006350 int err;
6351
6352 BT_DBG("%s", hdev->name);
6353
6354 if (!hdev_is_powered(hdev))
6355 return mgmt_cmd_complete(sk, hdev->id,
6356 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6357 MGMT_STATUS_NOT_POWERED,
6358 &cp->type, sizeof(cp->type));
6359
6360 switch (cp->type) {
6361 case BIT(BDADDR_BREDR):
6362 status = mgmt_bredr_support(hdev);
6363 if (status)
6364 return mgmt_cmd_complete(sk, hdev->id,
6365 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6366 status, &cp->type,
6367 sizeof(cp->type));
6368 eir_len = 5;
6369 break;
6370 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6371 status = mgmt_le_support(hdev);
6372 if (status)
6373 return mgmt_cmd_complete(sk, hdev->id,
6374 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6375 status, &cp->type,
6376 sizeof(cp->type));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006377 eir_len = 9 + 3 + 18 + 18 + 3;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006378 break;
6379 default:
6380 return mgmt_cmd_complete(sk, hdev->id,
6381 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6382 MGMT_STATUS_INVALID_PARAMS,
6383 &cp->type, sizeof(cp->type));
6384 }
6385
6386 hci_dev_lock(hdev);
6387
6388 rp_len = sizeof(*rp) + eir_len;
6389 rp = kmalloc(rp_len, GFP_ATOMIC);
6390 if (!rp) {
6391 hci_dev_unlock(hdev);
6392 return -ENOMEM;
6393 }
6394
6395 eir_len = 0;
6396 switch (cp->type) {
6397 case BIT(BDADDR_BREDR):
6398 eir_len = eir_append_data(rp->eir, eir_len, EIR_CLASS_OF_DEV,
6399 hdev->dev_class, 3);
6400 break;
6401 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07006402 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6403 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006404 hci_dev_unlock(hdev);
6405 err = mgmt_cmd_complete(sk, hdev->id,
Marcel Holtmann5082a592015-03-16 12:39:00 -07006406 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6407 MGMT_STATUS_FAILED,
6408 &cp->type, sizeof(cp->type));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006409 goto done;
6410 }
6411
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006412 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
6413 memcpy(addr, &hdev->rpa, 6);
6414 addr[6] = 0x01;
6415 } else if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
6416 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
6417 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
6418 bacmp(&hdev->static_addr, BDADDR_ANY))) {
6419 memcpy(addr, &hdev->static_addr, 6);
6420 addr[6] = 0x01;
6421 } else {
6422 memcpy(addr, &hdev->bdaddr, 6);
6423 addr[6] = 0x00;
6424 }
6425
6426 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
6427 addr, sizeof(addr));
6428
6429 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
6430 role = 0x02;
6431 else
6432 role = 0x01;
6433
6434 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
6435 &role, sizeof(role));
6436
Marcel Holtmann5082a592015-03-16 12:39:00 -07006437 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
6438 eir_len = eir_append_data(rp->eir, eir_len,
6439 EIR_LE_SC_CONFIRM,
6440 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006441
Marcel Holtmann5082a592015-03-16 12:39:00 -07006442 eir_len = eir_append_data(rp->eir, eir_len,
6443 EIR_LE_SC_RANDOM,
6444 rand, sizeof(rand));
6445 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006446
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006447 flags = get_adv_discov_flags(hdev);
6448
6449 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
6450 flags |= LE_AD_NO_BREDR;
6451
6452 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
6453 &flags, sizeof(flags));
6454 break;
6455 }
6456
6457 rp->type = cp->type;
6458 rp->eir_len = cpu_to_le16(eir_len);
6459
6460 hci_dev_unlock(hdev);
6461
Marcel Holtmann72000df2015-03-16 16:11:21 -07006462 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
6463
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006464 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann5425f982015-03-16 16:05:44 -07006465 MGMT_STATUS_SUCCESS, rp, sizeof(*rp) + eir_len);
Marcel Holtmann72000df2015-03-16 16:11:21 -07006466 if (err < 0)
6467 goto done;
6468
6469 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6470 rp, sizeof(*rp) + eir_len,
6471 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006472
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006473done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006474 kfree(rp);
6475
6476 return err;
6477}
6478
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006479static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6480 void *data, u16 data_len)
6481{
6482 struct mgmt_rp_read_adv_features *rp;
6483 size_t rp_len;
6484 int err;
6485
6486 BT_DBG("%s", hdev->name);
6487
6488 hci_dev_lock(hdev);
6489
6490 rp_len = sizeof(*rp);
6491 rp = kmalloc(rp_len, GFP_ATOMIC);
6492 if (!rp) {
6493 hci_dev_unlock(hdev);
6494 return -ENOMEM;
6495 }
6496
6497 rp->supported_flags = cpu_to_le32(0);
6498 rp->max_adv_data_len = 31;
6499 rp->max_scan_rsp_len = 31;
6500 rp->max_instances = 0;
6501 rp->num_instances = 0;
6502
6503 hci_dev_unlock(hdev);
6504
6505 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6506 MGMT_STATUS_SUCCESS, rp, rp_len);
6507
6508 kfree(rp);
6509
6510 return err;
6511}
6512
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006513static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006514 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006515 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006516 HCI_MGMT_NO_HDEV |
6517 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006518 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006519 HCI_MGMT_NO_HDEV |
6520 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006521 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006522 HCI_MGMT_NO_HDEV |
6523 HCI_MGMT_UNTRUSTED },
6524 { read_controller_info, MGMT_READ_INFO_SIZE,
6525 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006526 { set_powered, MGMT_SETTING_SIZE },
6527 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6528 { set_connectable, MGMT_SETTING_SIZE },
6529 { set_fast_connectable, MGMT_SETTING_SIZE },
6530 { set_bondable, MGMT_SETTING_SIZE },
6531 { set_link_security, MGMT_SETTING_SIZE },
6532 { set_ssp, MGMT_SETTING_SIZE },
6533 { set_hs, MGMT_SETTING_SIZE },
6534 { set_le, MGMT_SETTING_SIZE },
6535 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6536 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6537 { add_uuid, MGMT_ADD_UUID_SIZE },
6538 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006539 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6540 HCI_MGMT_VAR_LEN },
6541 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6542 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006543 { disconnect, MGMT_DISCONNECT_SIZE },
6544 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6545 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6546 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6547 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6548 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6549 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6550 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6551 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6552 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6553 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6554 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006555 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6556 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6557 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006558 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6559 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6560 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6561 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6562 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6563 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6564 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6565 { set_advertising, MGMT_SETTING_SIZE },
6566 { set_bredr, MGMT_SETTING_SIZE },
6567 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6568 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6569 { set_secure_conn, MGMT_SETTING_SIZE },
6570 { set_debug_keys, MGMT_SETTING_SIZE },
6571 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006572 { load_irks, MGMT_LOAD_IRKS_SIZE,
6573 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006574 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6575 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6576 { add_device, MGMT_ADD_DEVICE_SIZE },
6577 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006578 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6579 HCI_MGMT_VAR_LEN },
6580 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006581 HCI_MGMT_NO_HDEV |
6582 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006583 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006584 HCI_MGMT_UNCONFIGURED |
6585 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006586 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6587 HCI_MGMT_UNCONFIGURED },
6588 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6589 HCI_MGMT_UNCONFIGURED },
6590 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6591 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006592 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006593 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006594 HCI_MGMT_NO_HDEV |
6595 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006596 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006597};
6598
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006599int mgmt_control(struct hci_mgmt_chan *chan, struct sock *sk,
6600 struct msghdr *msg, size_t msglen)
Johan Hedberg03811012010-12-08 00:21:06 +02006601{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03006602 void *buf;
6603 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02006604 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01006605 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006606 struct hci_dev *hdev = NULL;
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006607 const struct hci_mgmt_handler *handler;
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006608 bool var_len, no_hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02006609 int err;
6610
6611 BT_DBG("got %zu bytes", msglen);
6612
6613 if (msglen < sizeof(*hdr))
6614 return -EINVAL;
6615
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03006616 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02006617 if (!buf)
6618 return -ENOMEM;
6619
Al Viro6ce8e9c2014-04-06 21:25:44 -04006620 if (memcpy_from_msg(buf, msg, msglen)) {
Johan Hedberg03811012010-12-08 00:21:06 +02006621 err = -EFAULT;
6622 goto done;
6623 }
6624
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03006625 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07006626 opcode = __le16_to_cpu(hdr->opcode);
6627 index = __le16_to_cpu(hdr->index);
6628 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02006629
6630 if (len != msglen - sizeof(*hdr)) {
6631 err = -EINVAL;
6632 goto done;
6633 }
6634
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006635 if (opcode >= chan->handler_count ||
6636 chan->handlers[opcode].func == NULL) {
6637 BT_DBG("Unknown op %u", opcode);
Johan Hedberga69e8372015-03-06 21:08:53 +02006638 err = mgmt_cmd_status(sk, index, opcode,
6639 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006640 goto done;
6641 }
6642
6643 handler = &chan->handlers[opcode];
6644
Marcel Holtmannc927a102015-03-14 19:28:03 -07006645 if (!hci_sock_test_flag(sk, HCI_SOCK_TRUSTED) &&
6646 !(handler->flags & HCI_MGMT_UNTRUSTED)) {
6647 err = mgmt_cmd_status(sk, index, opcode,
6648 MGMT_STATUS_PERMISSION_DENIED);
6649 goto done;
6650 }
6651
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006652 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006653 hdev = hci_dev_get(index);
6654 if (!hdev) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006655 err = mgmt_cmd_status(sk, index, opcode,
6656 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006657 goto done;
6658 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07006659
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006660 if (hci_dev_test_flag(hdev, HCI_SETUP) ||
6661 hci_dev_test_flag(hdev, HCI_CONFIG) ||
6662 hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006663 err = mgmt_cmd_status(sk, index, opcode,
6664 MGMT_STATUS_INVALID_INDEX);
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07006665 goto done;
6666 }
Marcel Holtmann42a9bc142014-07-04 16:54:40 +02006667
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006668 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006669 !(handler->flags & HCI_MGMT_UNCONFIGURED)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006670 err = mgmt_cmd_status(sk, index, opcode,
6671 MGMT_STATUS_INVALID_INDEX);
Marcel Holtmann42a9bc142014-07-04 16:54:40 +02006672 goto done;
6673 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006674 }
6675
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006676 no_hdev = (handler->flags & HCI_MGMT_NO_HDEV);
6677 if (no_hdev != !hdev) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006678 err = mgmt_cmd_status(sk, index, opcode,
6679 MGMT_STATUS_INVALID_INDEX);
Marcel Holtmann73d1df22014-07-02 22:10:52 +02006680 goto done;
6681 }
6682
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006683 var_len = (handler->flags & HCI_MGMT_VAR_LEN);
6684 if ((var_len && len < handler->data_len) ||
6685 (!var_len && len != handler->data_len)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006686 err = mgmt_cmd_status(sk, index, opcode,
6687 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02006688 goto done;
6689 }
6690
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006691 if (hdev)
6692 mgmt_init_hdev(sk, hdev);
6693
6694 cp = buf + sizeof(*hdr);
6695
Johan Hedbergbe22b542012-03-01 22:24:41 +02006696 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02006697 if (err < 0)
6698 goto done;
6699
Johan Hedberg03811012010-12-08 00:21:06 +02006700 err = msglen;
6701
6702done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006703 if (hdev)
6704 hci_dev_put(hdev);
6705
Johan Hedberg03811012010-12-08 00:21:06 +02006706 kfree(buf);
6707 return err;
6708}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006709
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006710void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006711{
Marcel Holtmannced85542015-03-14 19:27:56 -07006712 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006713
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006714 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6715 return;
6716
Marcel Holtmannf9207332015-03-14 19:27:55 -07006717 switch (hdev->dev_type) {
6718 case HCI_BREDR:
6719 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6720 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6721 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006722 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006723 } else {
6724 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6725 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006726 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006727 }
6728 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006729 case HCI_AMP:
6730 ev.type = 0x02;
6731 break;
6732 default:
6733 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006734 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006735
6736 ev.bus = hdev->bus;
6737
6738 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6739 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006740}
6741
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006742void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006743{
Marcel Holtmannced85542015-03-14 19:27:56 -07006744 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006745 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006746
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006747 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6748 return;
6749
Marcel Holtmannf9207332015-03-14 19:27:55 -07006750 switch (hdev->dev_type) {
6751 case HCI_BREDR:
6752 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006753
Marcel Holtmannf9207332015-03-14 19:27:55 -07006754 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6755 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6756 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006757 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006758 } else {
6759 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6760 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006761 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006762 }
6763 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006764 case HCI_AMP:
6765 ev.type = 0x02;
6766 break;
6767 default:
6768 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006769 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006770
6771 ev.bus = hdev->bus;
6772
6773 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6774 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006775}
6776
Andre Guedes6046dc32014-02-26 20:21:51 -03006777/* This function requires the caller holds hdev->lock */
Johan Hedberg2cf22212014-12-19 22:26:00 +02006778static void restart_le_actions(struct hci_request *req)
Andre Guedes6046dc32014-02-26 20:21:51 -03006779{
Johan Hedberg2cf22212014-12-19 22:26:00 +02006780 struct hci_dev *hdev = req->hdev;
Andre Guedes6046dc32014-02-26 20:21:51 -03006781 struct hci_conn_params *p;
6782
6783 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006784 /* Needed for AUTO_OFF case where might not "really"
6785 * have been powered off.
6786 */
6787 list_del_init(&p->action);
6788
6789 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006790 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006791 case HCI_AUTO_CONN_ALWAYS:
6792 list_add(&p->action, &hdev->pend_le_conns);
6793 break;
6794 case HCI_AUTO_CONN_REPORT:
6795 list_add(&p->action, &hdev->pend_le_reports);
6796 break;
6797 default:
6798 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006799 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006800 }
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006801
Johan Hedberg2cf22212014-12-19 22:26:00 +02006802 __hci_update_background_scan(req);
Andre Guedes6046dc32014-02-26 20:21:51 -03006803}
6804
Marcel Holtmann1904a852015-01-11 13:50:44 -08006805static void powered_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg229ab392013-03-15 17:06:53 -05006806{
6807 struct cmd_lookup match = { NULL, hdev };
6808
6809 BT_DBG("status 0x%02x", status);
6810
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006811 if (!status) {
6812 /* Register the available SMP channels (BR/EDR and LE) only
6813 * when successfully powering on the controller. This late
6814 * registration is required so that LE SMP can clearly
6815 * decide if the public address or static address is used.
6816 */
6817 smp_register(hdev);
6818 }
6819
Johan Hedberg229ab392013-03-15 17:06:53 -05006820 hci_dev_lock(hdev);
6821
6822 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6823
6824 new_settings(hdev, match.sk);
6825
6826 hci_dev_unlock(hdev);
6827
6828 if (match.sk)
6829 sock_put(match.sk);
6830}
6831
Johan Hedberg70da6242013-03-15 17:06:51 -05006832static int powered_update_hci(struct hci_dev *hdev)
6833{
Johan Hedberg890ea892013-03-15 17:06:52 -05006834 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05006835 u8 link_sec;
6836
Johan Hedberg890ea892013-03-15 17:06:52 -05006837 hci_req_init(&req, hdev);
6838
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006839 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED) &&
Johan Hedberg70da6242013-03-15 17:06:51 -05006840 !lmp_host_ssp_capable(hdev)) {
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006841 u8 mode = 0x01;
Johan Hedberg70da6242013-03-15 17:06:51 -05006842
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006843 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
Johan Hedberg70da6242013-03-15 17:06:51 -05006844
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006845 if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) {
6846 u8 support = 0x01;
6847
6848 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT,
6849 sizeof(support), &support);
6850 }
Johan Hedbergec6f99b2014-12-12 13:30:11 +02006851 }
6852
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006853 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
Johan Hedbergc73eee92013-04-19 18:35:21 +03006854 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05006855 struct hci_cp_write_le_host_supported cp;
6856
Marcel Holtmann32226e42014-07-24 20:04:16 +02006857 cp.le = 0x01;
6858 cp.simul = 0x00;
Johan Hedberg70da6242013-03-15 17:06:51 -05006859
6860 /* Check first if we already have the right
6861 * host state (host features set)
6862 */
6863 if (cp.le != lmp_host_le_capable(hdev) ||
6864 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05006865 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
6866 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05006867 }
6868
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07006869 if (lmp_le_capable(hdev)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006870 /* Make sure the controller has a good default for
6871 * advertising data. This also applies to the case
6872 * where BR/EDR was toggled during the AUTO_OFF phase.
6873 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006874 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07006875 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07006876 update_scan_rsp_data(&req);
6877 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006878
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006879 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07006880 enable_advertising(&req);
Johan Hedberg2cf22212014-12-19 22:26:00 +02006881
6882 restart_le_actions(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03006883 }
6884
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006885 link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg70da6242013-03-15 17:06:51 -05006886 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05006887 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
6888 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05006889
6890 if (lmp_bredr_capable(hdev)) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006891 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg406ef2a2015-03-10 20:14:27 +02006892 write_fast_connectable(&req, true);
6893 else
6894 write_fast_connectable(&req, false);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02006895 __hci_update_page_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006896 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05006897 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006898 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05006899 }
6900
Johan Hedberg229ab392013-03-15 17:06:53 -05006901 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05006902}
6903
Johan Hedberg744cf192011-11-08 20:40:14 +02006904int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006905{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006906 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006907 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006908 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006909
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006910 if (!hci_dev_test_flag(hdev, HCI_MGMT))
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006911 return 0;
6912
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006913 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05006914 if (powered_update_hci(hdev) == 0)
6915 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02006916
Johan Hedberg229ab392013-03-15 17:06:53 -05006917 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
6918 &match);
6919 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006920 }
6921
Johan Hedberg229ab392013-03-15 17:06:53 -05006922 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006923
6924 /* If the power off is because of hdev unregistration let
6925 * use the appropriate INVALID_INDEX status. Otherwise use
6926 * NOT_POWERED. We cover both scenarios here since later in
6927 * mgmt_index_removed() any hci_conn callbacks will have already
6928 * been triggered, potentially causing misleading DISCONNECTED
6929 * status responses.
6930 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006931 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006932 status = MGMT_STATUS_INVALID_INDEX;
6933 else
6934 status = MGMT_STATUS_NOT_POWERED;
6935
6936 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006937
6938 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07006939 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6940 zero_cod, sizeof(zero_cod), NULL);
Johan Hedberg229ab392013-03-15 17:06:53 -05006941
6942new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02006943 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006944
6945 if (match.sk)
6946 sock_put(match.sk);
6947
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006948 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006949}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006950
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006951void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006952{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006953 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006954 u8 status;
6955
Johan Hedberg333ae952015-03-17 13:48:47 +02006956 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006957 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006958 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006959
6960 if (err == -ERFKILL)
6961 status = MGMT_STATUS_RFKILLED;
6962 else
6963 status = MGMT_STATUS_FAILED;
6964
Johan Hedberga69e8372015-03-06 21:08:53 +02006965 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006966
6967 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006968}
6969
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006970void mgmt_discoverable_timeout(struct hci_dev *hdev)
6971{
6972 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006973
6974 hci_dev_lock(hdev);
6975
6976 /* When discoverable timeout triggers, then just make sure
6977 * the limited discoverable flag is cleared. Even in the case
6978 * of a timeout triggered from general discoverable, it is
6979 * safe to unconditionally clear the flag.
6980 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006981 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
6982 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006983
6984 hci_req_init(&req, hdev);
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006985 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg4b580612013-10-19 23:38:21 +03006986 u8 scan = SCAN_PAGE;
6987 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
6988 sizeof(scan), &scan);
6989 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006990 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03006991 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006992 hci_req_run(&req, NULL);
6993
6994 hdev->discov_timeout = 0;
6995
Johan Hedberg9a43e252013-10-20 19:00:07 +03006996 new_settings(hdev, NULL);
6997
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006998 hci_dev_unlock(hdev);
6999}
7000
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007001void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
7002 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007003{
Johan Hedberg86742e12011-11-07 23:13:38 +02007004 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007005
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007006 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007007
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007008 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02007009 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007010 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007011 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03007012 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03007013 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007014
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07007015 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007016}
Johan Hedbergf7520542011-01-20 12:34:39 +02007017
Johan Hedbergd7b25452014-05-23 13:19:53 +03007018static u8 mgmt_ltk_type(struct smp_ltk *ltk)
7019{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03007020 switch (ltk->type) {
7021 case SMP_LTK:
7022 case SMP_LTK_SLAVE:
7023 if (ltk->authenticated)
7024 return MGMT_LTK_AUTHENTICATED;
7025 return MGMT_LTK_UNAUTHENTICATED;
7026 case SMP_LTK_P256:
7027 if (ltk->authenticated)
7028 return MGMT_LTK_P256_AUTH;
7029 return MGMT_LTK_P256_UNAUTH;
7030 case SMP_LTK_P256_DEBUG:
7031 return MGMT_LTK_P256_DEBUG;
7032 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03007033
7034 return MGMT_LTK_UNAUTHENTICATED;
7035}
7036
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007037void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007038{
7039 struct mgmt_ev_new_long_term_key ev;
7040
7041 memset(&ev, 0, sizeof(ev));
7042
Marcel Holtmann5192d302014-02-19 17:11:58 -08007043 /* Devices using resolvable or non-resolvable random addresses
7044 * without providing an indentity resolving key don't require
7045 * to store long term keys. Their addresses will change the
7046 * next time around.
7047 *
7048 * Only when a remote device provides an identity address
7049 * make sure the long term key is stored. If the remote
7050 * identity is known, the long term keys are internally
7051 * mapped to the identity address. So allow static random
7052 * and public addresses here.
7053 */
Johan Hedbergba74b662014-02-19 14:57:45 +02007054 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7055 (key->bdaddr.b[5] & 0xc0) != 0xc0)
7056 ev.store_hint = 0x00;
7057 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007058 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02007059
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007060 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007061 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03007062 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007063 ev.key.enc_size = key->enc_size;
7064 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08007065 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007066
Johan Hedberg2ceba532014-06-16 19:25:16 +03007067 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007068 ev.key.master = 1;
7069
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007070 memcpy(ev.key.val, key->val, sizeof(key->val));
7071
Marcel Holtmann083368f2013-10-15 14:26:29 -07007072 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007073}
7074
Johan Hedberg95fbac82014-02-19 15:18:31 +02007075void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk)
7076{
7077 struct mgmt_ev_new_irk ev;
7078
7079 memset(&ev, 0, sizeof(ev));
7080
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08007081 /* For identity resolving keys from devices that are already
7082 * using a public address or static random address, do not
7083 * ask for storing this key. The identity resolving key really
7084 * is only mandatory for devices using resovlable random
7085 * addresses.
7086 *
7087 * Storing all identity resolving keys has the downside that
7088 * they will be also loaded on next boot of they system. More
7089 * identity resolving keys, means more time during scanning is
7090 * needed to actually resolve these addresses.
7091 */
7092 if (bacmp(&irk->rpa, BDADDR_ANY))
7093 ev.store_hint = 0x01;
7094 else
7095 ev.store_hint = 0x00;
7096
Johan Hedberg95fbac82014-02-19 15:18:31 +02007097 bacpy(&ev.rpa, &irk->rpa);
7098 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
7099 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
7100 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
7101
7102 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
7103}
7104
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007105void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
7106 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007107{
7108 struct mgmt_ev_new_csrk ev;
7109
7110 memset(&ev, 0, sizeof(ev));
7111
7112 /* Devices using resolvable or non-resolvable random addresses
7113 * without providing an indentity resolving key don't require
7114 * to store signature resolving keys. Their addresses will change
7115 * the next time around.
7116 *
7117 * Only when a remote device provides an identity address
7118 * make sure the signature resolving key is stored. So allow
7119 * static random and public addresses here.
7120 */
7121 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7122 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
7123 ev.store_hint = 0x00;
7124 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007125 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007126
7127 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
7128 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02007129 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007130 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
7131
7132 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
7133}
7134
Andre Guedesffb5a8272014-07-01 18:10:11 -03007135void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03007136 u8 bdaddr_type, u8 store_hint, u16 min_interval,
7137 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03007138{
7139 struct mgmt_ev_new_conn_param ev;
7140
Johan Hedbergc103aea2014-07-02 17:37:34 +03007141 if (!hci_is_identity_address(bdaddr, bdaddr_type))
7142 return;
7143
Andre Guedesffb5a8272014-07-01 18:10:11 -03007144 memset(&ev, 0, sizeof(ev));
7145 bacpy(&ev.addr.bdaddr, bdaddr);
7146 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03007147 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03007148 ev.min_interval = cpu_to_le16(min_interval);
7149 ev.max_interval = cpu_to_le16(max_interval);
7150 ev.latency = cpu_to_le16(latency);
7151 ev.timeout = cpu_to_le16(timeout);
7152
7153 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
7154}
7155
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007156void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
7157 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02007158{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007159 char buf[512];
7160 struct mgmt_ev_device_connected *ev = (void *) buf;
7161 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02007162
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007163 bacpy(&ev->addr.bdaddr, &conn->dst);
7164 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02007165
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02007166 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02007167
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007168 /* We must ensure that the EIR Data fields are ordered and
7169 * unique. Keep it simple for now and avoid the problem by not
7170 * adding any BR/EDR data to the LE adv.
7171 */
7172 if (conn->le_adv_data_len > 0) {
7173 memcpy(&ev->eir[eir_len],
7174 conn->le_adv_data, conn->le_adv_data_len);
7175 eir_len = conn->le_adv_data_len;
7176 } else {
7177 if (name_len > 0)
7178 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
7179 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007180
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00007181 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007182 eir_len = eir_append_data(ev->eir, eir_len,
7183 EIR_CLASS_OF_DEV,
7184 conn->dev_class, 3);
7185 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02007186
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007187 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007188
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07007189 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
7190 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02007191}
7192
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007193static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007194{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007195 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007196
Johan Hedbergf5818c22014-12-05 13:36:02 +02007197 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007198
7199 *sk = cmd->sk;
7200 sock_hold(*sk);
7201
Johan Hedberga664b5b2011-02-19 12:06:02 -03007202 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007203}
7204
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007205static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007206{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007207 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007208 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007209
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007210 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7211
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007212 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007213 mgmt_pending_remove(cmd);
7214}
7215
Johan Hedberg84c61d92014-08-01 11:13:30 +03007216bool mgmt_powering_down(struct hci_dev *hdev)
7217{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007218 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007219 struct mgmt_mode *cp;
7220
Johan Hedberg333ae952015-03-17 13:48:47 +02007221 cmd = pending_find(MGMT_OP_SET_POWERED, hdev);
Johan Hedberg84c61d92014-08-01 11:13:30 +03007222 if (!cmd)
7223 return false;
7224
7225 cp = cmd->param;
7226 if (!cp->val)
7227 return true;
7228
7229 return false;
7230}
7231
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007232void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007233 u8 link_type, u8 addr_type, u8 reason,
7234 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007235{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007236 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007237 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007238
Johan Hedberg84c61d92014-08-01 11:13:30 +03007239 /* The connection is still in hci_conn_hash so test for 1
7240 * instead of 0 to know if this is the last one.
7241 */
7242 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7243 cancel_delayed_work(&hdev->power_off);
7244 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007245 }
7246
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007247 if (!mgmt_connected)
7248 return;
7249
Andre Guedes57eb7762013-10-30 19:01:41 -03007250 if (link_type != ACL_LINK && link_type != LE_LINK)
7251 return;
7252
Johan Hedberg744cf192011-11-08 20:40:14 +02007253 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007254
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007255 bacpy(&ev.addr.bdaddr, bdaddr);
7256 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7257 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007258
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007259 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007260
7261 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007262 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007263
Johan Hedberg124f6e32012-02-09 13:50:12 +02007264 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007265 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007266}
7267
Marcel Holtmann78929242013-10-06 23:55:47 -07007268void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7269 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007270{
Andre Guedes3655bba2013-10-30 19:01:40 -03007271 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7272 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007273 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007274
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007275 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7276 hdev);
7277
Johan Hedberg333ae952015-03-17 13:48:47 +02007278 cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007279 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007280 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007281
Andre Guedes3655bba2013-10-30 19:01:40 -03007282 cp = cmd->param;
7283
7284 if (bacmp(bdaddr, &cp->addr.bdaddr))
7285 return;
7286
7287 if (cp->addr.type != bdaddr_type)
7288 return;
7289
Johan Hedbergf5818c22014-12-05 13:36:02 +02007290 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007291 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007292}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007293
Marcel Holtmann445608d2013-10-06 23:55:48 -07007294void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7295 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007296{
7297 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007298
Johan Hedberg84c61d92014-08-01 11:13:30 +03007299 /* The connection is still in hci_conn_hash so test for 1
7300 * instead of 0 to know if this is the last one.
7301 */
7302 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7303 cancel_delayed_work(&hdev->power_off);
7304 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007305 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007306
Johan Hedberg4c659c32011-11-07 23:13:39 +02007307 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007308 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007309 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007310
Marcel Holtmann445608d2013-10-06 23:55:48 -07007311 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007312}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007313
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007314void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007315{
7316 struct mgmt_ev_pin_code_request ev;
7317
Johan Hedbergd8457692012-02-17 14:24:57 +02007318 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007319 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007320 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007321
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007322 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007323}
7324
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007325void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7326 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007327{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007328 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007329
Johan Hedberg333ae952015-03-17 13:48:47 +02007330 cmd = pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007331 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007332 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007333
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007334 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007335 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007336}
7337
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007338void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7339 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007340{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007341 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007342
Johan Hedberg333ae952015-03-17 13:48:47 +02007343 cmd = pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007344 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007345 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007346
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007347 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007348 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007349}
Johan Hedberga5c29682011-02-19 12:05:57 -03007350
Johan Hedberg744cf192011-11-08 20:40:14 +02007351int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007352 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007353 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007354{
7355 struct mgmt_ev_user_confirm_request ev;
7356
Johan Hedberg744cf192011-11-08 20:40:14 +02007357 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007358
Johan Hedberg272d90d2012-02-09 15:26:12 +02007359 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007360 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007361 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007362 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007363
Johan Hedberg744cf192011-11-08 20:40:14 +02007364 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007365 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007366}
7367
Johan Hedberg272d90d2012-02-09 15:26:12 +02007368int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007369 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007370{
7371 struct mgmt_ev_user_passkey_request ev;
7372
7373 BT_DBG("%s", hdev->name);
7374
Johan Hedberg272d90d2012-02-09 15:26:12 +02007375 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007376 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08007377
7378 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007379 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007380}
7381
Brian Gix0df4c182011-11-16 13:53:13 -08007382static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007383 u8 link_type, u8 addr_type, u8 status,
7384 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007385{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007386 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007387
Johan Hedberg333ae952015-03-17 13:48:47 +02007388 cmd = pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007389 if (!cmd)
7390 return -ENOENT;
7391
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007392 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007393 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007394
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007395 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007396}
7397
Johan Hedberg744cf192011-11-08 20:40:14 +02007398int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007399 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007400{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007401 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007402 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007403}
7404
Johan Hedberg272d90d2012-02-09 15:26:12 +02007405int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007406 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007407{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007408 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007409 status,
7410 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007411}
Johan Hedberg2a611692011-02-19 12:06:00 -03007412
Brian Gix604086b2011-11-23 08:28:33 -08007413int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007414 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007415{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007416 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007417 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007418}
7419
Johan Hedberg272d90d2012-02-09 15:26:12 +02007420int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007421 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007422{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007423 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007424 status,
7425 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007426}
7427
Johan Hedberg92a25252012-09-06 18:39:26 +03007428int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7429 u8 link_type, u8 addr_type, u32 passkey,
7430 u8 entered)
7431{
7432 struct mgmt_ev_passkey_notify ev;
7433
7434 BT_DBG("%s", hdev->name);
7435
7436 bacpy(&ev.addr.bdaddr, bdaddr);
7437 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7438 ev.passkey = __cpu_to_le32(passkey);
7439 ev.entered = entered;
7440
7441 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7442}
7443
Johan Hedberge1e930f2014-09-08 17:09:49 -07007444void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007445{
7446 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007447 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007448 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007449
Johan Hedberge1e930f2014-09-08 17:09:49 -07007450 bacpy(&ev.addr.bdaddr, &conn->dst);
7451 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7452 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007453
Johan Hedberge1e930f2014-09-08 17:09:49 -07007454 cmd = find_pairing(conn);
7455
7456 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7457 cmd ? cmd->sk : NULL);
7458
Johan Hedberga511b352014-12-11 21:45:45 +02007459 if (cmd) {
7460 cmd->cmd_complete(cmd, status);
7461 mgmt_pending_remove(cmd);
7462 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007463}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007464
Marcel Holtmann464996a2013-10-15 14:26:24 -07007465void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007466{
7467 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007468 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007469
7470 if (status) {
7471 u8 mgmt_err = mgmt_status(status);
7472 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007473 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007474 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007475 }
7476
Marcel Holtmann464996a2013-10-15 14:26:24 -07007477 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007478 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007479 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007480 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007481
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007482 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007483 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007484
Johan Hedberg47990ea2012-02-22 11:58:37 +02007485 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007486 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007487
7488 if (match.sk)
7489 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007490}
7491
Johan Hedberg890ea892013-03-15 17:06:52 -05007492static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007493{
Johan Hedberg890ea892013-03-15 17:06:52 -05007494 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007495 struct hci_cp_write_eir cp;
7496
Johan Hedberg976eb202012-10-24 21:12:01 +03007497 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007498 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007499
Johan Hedbergc80da272012-02-22 15:38:48 +02007500 memset(hdev->eir, 0, sizeof(hdev->eir));
7501
Johan Hedbergcacaf522012-02-21 00:52:42 +02007502 memset(&cp, 0, sizeof(cp));
7503
Johan Hedberg890ea892013-03-15 17:06:52 -05007504 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007505}
7506
Marcel Holtmann3e248562013-10-15 14:26:25 -07007507void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007508{
7509 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007510 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007511 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007512
7513 if (status) {
7514 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007515
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007516 if (enable && hci_dev_test_and_clear_flag(hdev,
7517 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007518 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007519 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007520 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007521
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007522 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7523 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007524 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007525 }
7526
7527 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007528 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007529 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007530 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007531 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007532 changed = hci_dev_test_and_clear_flag(hdev,
7533 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007534 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007535 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007536 }
7537
7538 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7539
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007540 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007541 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007542
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007543 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007544 sock_put(match.sk);
7545
Johan Hedberg890ea892013-03-15 17:06:52 -05007546 hci_req_init(&req, hdev);
7547
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007548 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7549 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007550 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7551 sizeof(enable), &enable);
Johan Hedberg890ea892013-03-15 17:06:52 -05007552 update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007553 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007554 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007555 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007556
7557 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007558}
7559
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007560static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007561{
7562 struct cmd_lookup *match = data;
7563
Johan Hedberg90e70452012-02-23 23:09:40 +02007564 if (match->sk == NULL) {
7565 match->sk = cmd->sk;
7566 sock_hold(match->sk);
7567 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007568}
7569
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007570void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7571 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007572{
Johan Hedberg90e70452012-02-23 23:09:40 +02007573 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007574
Johan Hedberg92da6092013-03-15 17:06:55 -05007575 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7576 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7577 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007578
7579 if (!status)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007580 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7581 dev_class, 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02007582
7583 if (match.sk)
7584 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007585}
7586
Marcel Holtmann7667da32013-10-15 14:26:27 -07007587void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007588{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007589 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007590 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007591
Johan Hedberg13928972013-03-15 17:07:00 -05007592 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007593 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007594
7595 memset(&ev, 0, sizeof(ev));
7596 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007597 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007598
Johan Hedberg333ae952015-03-17 13:48:47 +02007599 cmd = pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007600 if (!cmd) {
7601 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007602
Johan Hedberg13928972013-03-15 17:07:00 -05007603 /* If this is a HCI command related to powering on the
7604 * HCI dev don't send any mgmt signals.
7605 */
Johan Hedberg333ae952015-03-17 13:48:47 +02007606 if (pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007607 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007608 }
7609
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007610 mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7611 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007612}
Szymon Jancc35938b2011-03-22 13:12:21 +01007613
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007614void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
Johan Hedberg38da1702014-11-17 20:52:20 +02007615 u8 *rand192, u8 *hash256, u8 *rand256,
7616 u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01007617{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007618 struct mgmt_pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01007619
Johan Hedberg744cf192011-11-08 20:40:14 +02007620 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01007621
Johan Hedberg333ae952015-03-17 13:48:47 +02007622 cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01007623 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07007624 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01007625
7626 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02007627 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
7628 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01007629 } else {
Johan Hedberg66f096f2015-02-02 13:23:42 +02007630 struct mgmt_rp_read_local_oob_data rp;
7631 size_t rp_size = sizeof(rp);
7632
7633 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
7634 memcpy(rp.rand192, rand192, sizeof(rp.rand192));
7635
Johan Hedberg710f11c2014-05-26 11:21:22 +03007636 if (bredr_sc_enabled(hdev) && hash256 && rand256) {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007637 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
Johan Hedberg38da1702014-11-17 20:52:20 +02007638 memcpy(rp.rand256, rand256, sizeof(rp.rand256));
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007639 } else {
Johan Hedberg66f096f2015-02-02 13:23:42 +02007640 rp_size -= sizeof(rp.hash256) + sizeof(rp.rand256);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007641 }
Johan Hedberg66f096f2015-02-02 13:23:42 +02007642
Johan Hedberg2a1afb52015-03-06 21:08:54 +02007643 mgmt_cmd_complete(cmd->sk, hdev->id,
7644 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
7645 &rp, rp_size);
Szymon Jancc35938b2011-03-22 13:12:21 +01007646 }
7647
7648 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01007649}
Johan Hedberge17acd42011-03-30 23:57:16 +03007650
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007651static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7652{
7653 int i;
7654
7655 for (i = 0; i < uuid_count; i++) {
7656 if (!memcmp(uuid, uuids[i], 16))
7657 return true;
7658 }
7659
7660 return false;
7661}
7662
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007663static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7664{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007665 u16 parsed = 0;
7666
7667 while (parsed < eir_len) {
7668 u8 field_len = eir[0];
7669 u8 uuid[16];
7670 int i;
7671
7672 if (field_len == 0)
7673 break;
7674
7675 if (eir_len - parsed < field_len + 1)
7676 break;
7677
7678 switch (eir[1]) {
7679 case EIR_UUID16_ALL:
7680 case EIR_UUID16_SOME:
7681 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007682 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007683 uuid[13] = eir[i + 3];
7684 uuid[12] = eir[i + 2];
7685 if (has_uuid(uuid, uuid_count, uuids))
7686 return true;
7687 }
7688 break;
7689 case EIR_UUID32_ALL:
7690 case EIR_UUID32_SOME:
7691 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007692 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007693 uuid[15] = eir[i + 5];
7694 uuid[14] = eir[i + 4];
7695 uuid[13] = eir[i + 3];
7696 uuid[12] = eir[i + 2];
7697 if (has_uuid(uuid, uuid_count, uuids))
7698 return true;
7699 }
7700 break;
7701 case EIR_UUID128_ALL:
7702 case EIR_UUID128_SOME:
7703 for (i = 0; i + 17 <= field_len; i += 16) {
7704 memcpy(uuid, eir + i + 2, 16);
7705 if (has_uuid(uuid, uuid_count, uuids))
7706 return true;
7707 }
7708 break;
7709 }
7710
7711 parsed += field_len + 1;
7712 eir += field_len + 1;
7713 }
7714
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007715 return false;
7716}
7717
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007718static void restart_le_scan(struct hci_dev *hdev)
7719{
7720 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007721 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007722 return;
7723
7724 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7725 hdev->discovery.scan_start +
7726 hdev->discovery.scan_duration))
7727 return;
7728
7729 queue_delayed_work(hdev->workqueue, &hdev->le_scan_restart,
7730 DISCOV_LE_RESTART_DELAY);
7731}
7732
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007733static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7734 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7735{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007736 /* If a RSSI threshold has been specified, and
7737 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7738 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7739 * is set, let it through for further processing, as we might need to
7740 * restart the scan.
7741 *
7742 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7743 * the results are also dropped.
7744 */
7745 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7746 (rssi == HCI_RSSI_INVALID ||
7747 (rssi < hdev->discovery.rssi &&
7748 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7749 return false;
7750
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007751 if (hdev->discovery.uuid_count != 0) {
7752 /* If a list of UUIDs is provided in filter, results with no
7753 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007754 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007755 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7756 hdev->discovery.uuids) &&
7757 !eir_has_uuids(scan_rsp, scan_rsp_len,
7758 hdev->discovery.uuid_count,
7759 hdev->discovery.uuids))
7760 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007761 }
7762
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007763 /* If duplicate filtering does not report RSSI changes, then restart
7764 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007765 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007766 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7767 restart_le_scan(hdev);
7768
7769 /* Validate RSSI value against the RSSI threshold once more. */
7770 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7771 rssi < hdev->discovery.rssi)
7772 return false;
7773 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007774
7775 return true;
7776}
7777
Marcel Holtmann901801b2013-10-06 23:55:51 -07007778void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007779 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7780 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007781{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007782 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007783 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007784 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007785
Johan Hedberg75ce2082014-07-02 22:42:01 +03007786 /* Don't send events for a non-kernel initiated discovery. With
7787 * LE one exception is if we have pend_le_reports > 0 in which
7788 * case we're doing passive scanning and want these events.
7789 */
7790 if (!hci_discovery_active(hdev)) {
7791 if (link_type == ACL_LINK)
7792 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007793 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007794 return;
7795 }
Andre Guedes12602d02013-04-30 15:29:40 -03007796
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007797 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007798 /* We are using service discovery */
7799 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7800 scan_rsp_len))
7801 return;
7802 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007803
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007804 /* Make sure that the buffer is big enough. The 5 extra bytes
7805 * are for the potential CoD field.
7806 */
7807 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007808 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007809
Johan Hedberg1dc06092012-01-15 21:01:23 +02007810 memset(buf, 0, sizeof(buf));
7811
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007812 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7813 * RSSI value was reported as 0 when not available. This behavior
7814 * is kept when using device discovery. This is required for full
7815 * backwards compatibility with the API.
7816 *
7817 * However when using service discovery, the value 127 will be
7818 * returned when the RSSI is not available.
7819 */
Szymon Janc91200e92015-01-22 16:57:05 +01007820 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7821 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007822 rssi = 0;
7823
Johan Hedberg841c5642014-07-07 12:45:54 +03007824 bacpy(&ev->addr.bdaddr, bdaddr);
7825 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007826 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007827 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007828
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007829 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007830 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007831 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007832
Johan Hedberg1dc06092012-01-15 21:01:23 +02007833 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
7834 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007835 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007836
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007837 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007838 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007839 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007840
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007841 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7842 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007843
Marcel Holtmann901801b2013-10-06 23:55:51 -07007844 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007845}
Johan Hedberga88a9652011-03-30 13:18:12 +03007846
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007847void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7848 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007849{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007850 struct mgmt_ev_device_found *ev;
7851 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7852 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007853
Johan Hedbergb644ba32012-01-17 21:48:47 +02007854 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007855
Johan Hedbergb644ba32012-01-17 21:48:47 +02007856 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007857
Johan Hedbergb644ba32012-01-17 21:48:47 +02007858 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007859 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007860 ev->rssi = rssi;
7861
7862 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007863 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007864
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007865 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007866
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007867 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007868}
Johan Hedberg314b2382011-04-27 10:29:57 -04007869
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007870void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007871{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007872 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007873
Andre Guedes343fb142011-11-22 17:14:19 -03007874 BT_DBG("%s discovering %u", hdev->name, discovering);
7875
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007876 memset(&ev, 0, sizeof(ev));
7877 ev.type = hdev->discovery.type;
7878 ev.discovering = discovering;
7879
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007880 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007881}
Antti Julku5e762442011-08-25 16:48:02 +03007882
Marcel Holtmann1904a852015-01-11 13:50:44 -08007883static void adv_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Marcel Holtmann5976e602013-10-06 04:08:14 -07007884{
7885 BT_DBG("%s status %u", hdev->name, status);
Marcel Holtmann5976e602013-10-06 04:08:14 -07007886}
7887
7888void mgmt_reenable_advertising(struct hci_dev *hdev)
7889{
7890 struct hci_request req;
7891
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007892 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Marcel Holtmann5976e602013-10-06 04:08:14 -07007893 return;
7894
7895 hci_req_init(&req, hdev);
7896 enable_advertising(&req);
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03007897 hci_req_run(&req, adv_enable_complete);
Marcel Holtmann5976e602013-10-06 04:08:14 -07007898}
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007899
7900static struct hci_mgmt_chan chan = {
7901 .channel = HCI_CHANNEL_CONTROL,
7902 .handler_count = ARRAY_SIZE(mgmt_handlers),
7903 .handlers = mgmt_handlers,
7904};
7905
7906int mgmt_init(void)
7907{
7908 return hci_mgmt_chan_register(&chan);
7909}
7910
7911void mgmt_exit(void)
7912{
7913 hci_mgmt_chan_unregister(&chan);
7914}