blob: 7bcdf61afe11a83b474811d02074e50c44fc905f [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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200295
Andre Guedes790eff42012-06-07 19:05:46 -0300296 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200312 kfree_skb(skb);
313
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300314 return err;
Johan Hedbergf7b64e692010-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 Hedbergaee9b212012-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200737
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700738 if (hci_dev_test_flag(hdev, HCI_HS_ENABLED))
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200739 settings |= MGMT_SETTING_HS;
740
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700741 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300742 settings |= MGMT_SETTING_ADVERTISING;
743
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700744 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800745 settings |= MGMT_SETTING_SECURE_CONN;
746
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700747 if (hci_dev_test_flag(hdev, HCI_KEEP_DEBUG_KEYS))
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800748 settings |= MGMT_SETTING_DEBUG_KEYS;
749
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700750 if (hci_dev_test_flag(hdev, HCI_PRIVACY))
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200751 settings |= MGMT_SETTING_PRIVACY;
752
Marcel Holtmann93690c22015-03-06 10:11:21 -0800753 /* The current setting for static address has two purposes. The
754 * first is to indicate if the static address will be used and
755 * the second is to indicate if it is actually set.
756 *
757 * This means if the static address is not configured, this flag
758 * will never bet set. If the address is configured, then if the
759 * address is actually used decides if the flag is set or not.
760 *
761 * For single mode LE only controllers and dual-mode controllers
762 * with BR/EDR disabled, the existence of the static address will
763 * be evaluated.
764 */
Marcel Holtmannb7cb93e2015-03-13 10:20:35 -0700765 if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700766 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Marcel Holtmann93690c22015-03-06 10:11:21 -0800767 !bacmp(&hdev->bdaddr, BDADDR_ANY)) {
768 if (bacmp(&hdev->static_addr, BDADDR_ANY))
769 settings |= MGMT_SETTING_STATIC_ADDRESS;
770 }
771
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200772 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200773}
774
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300775#define PNP_INFO_SVCLASS_ID 0x1200
776
Johan Hedberg213202e2013-01-27 00:31:33 +0200777static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
778{
779 u8 *ptr = data, *uuids_start = NULL;
780 struct bt_uuid *uuid;
781
782 if (len < 4)
783 return ptr;
784
785 list_for_each_entry(uuid, &hdev->uuids, list) {
786 u16 uuid16;
787
788 if (uuid->size != 16)
789 continue;
790
791 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
792 if (uuid16 < 0x1100)
793 continue;
794
795 if (uuid16 == PNP_INFO_SVCLASS_ID)
796 continue;
797
798 if (!uuids_start) {
799 uuids_start = ptr;
800 uuids_start[0] = 1;
801 uuids_start[1] = EIR_UUID16_ALL;
802 ptr += 2;
803 }
804
805 /* Stop if not enough space to put next UUID */
806 if ((ptr - data) + sizeof(u16) > len) {
807 uuids_start[1] = EIR_UUID16_SOME;
808 break;
809 }
810
811 *ptr++ = (uuid16 & 0x00ff);
812 *ptr++ = (uuid16 & 0xff00) >> 8;
813 uuids_start[0] += sizeof(uuid16);
814 }
815
816 return ptr;
817}
818
Johan Hedbergcdf19632013-01-27 00:31:34 +0200819static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
820{
821 u8 *ptr = data, *uuids_start = NULL;
822 struct bt_uuid *uuid;
823
824 if (len < 6)
825 return ptr;
826
827 list_for_each_entry(uuid, &hdev->uuids, list) {
828 if (uuid->size != 32)
829 continue;
830
831 if (!uuids_start) {
832 uuids_start = ptr;
833 uuids_start[0] = 1;
834 uuids_start[1] = EIR_UUID32_ALL;
835 ptr += 2;
836 }
837
838 /* Stop if not enough space to put next UUID */
839 if ((ptr - data) + sizeof(u32) > len) {
840 uuids_start[1] = EIR_UUID32_SOME;
841 break;
842 }
843
844 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
845 ptr += sizeof(u32);
846 uuids_start[0] += sizeof(u32);
847 }
848
849 return ptr;
850}
851
Johan Hedbergc00d5752013-01-27 00:31:35 +0200852static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
853{
854 u8 *ptr = data, *uuids_start = NULL;
855 struct bt_uuid *uuid;
856
857 if (len < 18)
858 return ptr;
859
860 list_for_each_entry(uuid, &hdev->uuids, list) {
861 if (uuid->size != 128)
862 continue;
863
864 if (!uuids_start) {
865 uuids_start = ptr;
866 uuids_start[0] = 1;
867 uuids_start[1] = EIR_UUID128_ALL;
868 ptr += 2;
869 }
870
871 /* Stop if not enough space to put next UUID */
872 if ((ptr - data) + 16 > len) {
873 uuids_start[1] = EIR_UUID128_SOME;
874 break;
875 }
876
877 memcpy(ptr, uuid->uuid, 16);
878 ptr += 16;
879 uuids_start[0] += 16;
880 }
881
882 return ptr;
883}
884
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200885static struct mgmt_pending_cmd *mgmt_pending_find(u16 opcode,
886 struct hci_dev *hdev)
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300887{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200888 struct mgmt_pending_cmd *cmd;
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300889
890 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
891 if (cmd->opcode == opcode)
892 return cmd;
893 }
894
895 return NULL;
896}
897
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200898static struct mgmt_pending_cmd *mgmt_pending_find_data(u16 opcode,
899 struct hci_dev *hdev,
900 const void *data)
Johan Hedberg95868422014-06-28 17:54:07 +0300901{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200902 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +0300903
904 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
905 if (cmd->user_data != data)
906 continue;
907 if (cmd->opcode == opcode)
908 return cmd;
909 }
910
911 return NULL;
912}
913
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700914static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
915{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700916 u8 ad_len = 0;
917 size_t name_len;
918
919 name_len = strlen(hdev->dev_name);
920 if (name_len > 0) {
921 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
922
923 if (name_len > max_len) {
924 name_len = max_len;
925 ptr[1] = EIR_NAME_SHORT;
926 } else
927 ptr[1] = EIR_NAME_COMPLETE;
928
929 ptr[0] = name_len + 1;
930
931 memcpy(ptr + 2, hdev->dev_name, name_len);
932
933 ad_len += (name_len + 2);
934 ptr += (name_len + 2);
935 }
936
937 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700938}
939
940static void update_scan_rsp_data(struct hci_request *req)
941{
942 struct hci_dev *hdev = req->hdev;
943 struct hci_cp_le_set_scan_rsp_data cp;
944 u8 len;
945
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700946 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700947 return;
948
949 memset(&cp, 0, sizeof(cp));
950
951 len = create_scan_rsp_data(hdev, cp.data);
952
Johan Hedbergeb438b52013-10-16 15:31:07 +0300953 if (hdev->scan_rsp_data_len == len &&
954 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700955 return;
956
Johan Hedbergeb438b52013-10-16 15:31:07 +0300957 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
958 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700959
960 cp.length = len;
961
962 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
963}
964
Johan Hedberg9a43e252013-10-20 19:00:07 +0300965static u8 get_adv_discov_flags(struct hci_dev *hdev)
966{
Johan Hedberg3b0602c2015-03-06 21:08:55 +0200967 struct mgmt_pending_cmd *cmd;
Johan Hedberg9a43e252013-10-20 19:00:07 +0300968
969 /* If there's a pending mgmt command the flags will not yet have
970 * their final values, so check for this first.
971 */
972 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
973 if (cmd) {
974 struct mgmt_mode *cp = cmd->param;
975 if (cp->val == 0x01)
976 return LE_AD_GENERAL;
977 else if (cp->val == 0x02)
978 return LE_AD_LIMITED;
979 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700980 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300981 return LE_AD_LIMITED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700982 else if (hci_dev_test_flag(hdev, HCI_DISCOVERABLE))
Johan Hedberg9a43e252013-10-20 19:00:07 +0300983 return LE_AD_GENERAL;
984 }
985
986 return 0;
987}
988
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700989static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700990{
991 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700992
Johan Hedberg9a43e252013-10-20 19:00:07 +0300993 flags |= get_adv_discov_flags(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700994
Marcel Holtmannd7a5a112015-03-13 02:11:00 -0700995 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700996 flags |= LE_AD_NO_BREDR;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700997
998 if (flags) {
999 BT_DBG("adv flags 0x%02x", flags);
1000
1001 ptr[0] = 2;
1002 ptr[1] = EIR_FLAGS;
1003 ptr[2] = flags;
1004
1005 ad_len += 3;
1006 ptr += 3;
1007 }
1008
1009 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
1010 ptr[0] = 2;
1011 ptr[1] = EIR_TX_POWER;
1012 ptr[2] = (u8) hdev->adv_tx_power;
1013
1014 ad_len += 3;
1015 ptr += 3;
1016 }
1017
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001018 return ad_len;
1019}
1020
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001021static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001022{
1023 struct hci_dev *hdev = req->hdev;
1024 struct hci_cp_le_set_adv_data cp;
1025 u8 len;
1026
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001027 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001028 return;
1029
1030 memset(&cp, 0, sizeof(cp));
1031
Marcel Holtmann46cad2e2013-10-16 00:16:46 -07001032 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001033
1034 if (hdev->adv_data_len == len &&
1035 memcmp(cp.data, hdev->adv_data, len) == 0)
1036 return;
1037
1038 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
1039 hdev->adv_data_len = len;
1040
1041 cp.length = len;
1042
1043 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
1044}
1045
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001046int mgmt_update_adv_data(struct hci_dev *hdev)
1047{
1048 struct hci_request req;
1049
1050 hci_req_init(&req, hdev);
1051 update_adv_data(&req);
1052
1053 return hci_req_run(&req, NULL);
1054}
1055
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001056static void create_eir(struct hci_dev *hdev, u8 *data)
1057{
1058 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001059 size_t name_len;
1060
1061 name_len = strlen(hdev->dev_name);
1062
1063 if (name_len > 0) {
1064 /* EIR Data type */
1065 if (name_len > 48) {
1066 name_len = 48;
1067 ptr[1] = EIR_NAME_SHORT;
1068 } else
1069 ptr[1] = EIR_NAME_COMPLETE;
1070
1071 /* EIR Data length */
1072 ptr[0] = name_len + 1;
1073
1074 memcpy(ptr + 2, hdev->dev_name, name_len);
1075
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001076 ptr += (name_len + 2);
1077 }
1078
Johan Hedbergbbaf4442012-11-08 01:22:59 +01001079 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -07001080 ptr[0] = 2;
1081 ptr[1] = EIR_TX_POWER;
1082 ptr[2] = (u8) hdev->inq_tx_power;
1083
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -07001084 ptr += 3;
1085 }
1086
Marcel Holtmann2b9be132012-03-11 19:32:12 -07001087 if (hdev->devid_source > 0) {
1088 ptr[0] = 9;
1089 ptr[1] = EIR_DEVICE_ID;
1090
1091 put_unaligned_le16(hdev->devid_source, ptr + 2);
1092 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
1093 put_unaligned_le16(hdev->devid_product, ptr + 6);
1094 put_unaligned_le16(hdev->devid_version, ptr + 8);
1095
Marcel Holtmann2b9be132012-03-11 19:32:12 -07001096 ptr += 10;
1097 }
1098
Johan Hedberg213202e2013-01-27 00:31:33 +02001099 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +02001100 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +02001101 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001102}
1103
Johan Hedberg890ea892013-03-15 17:06:52 -05001104static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001105{
Johan Hedberg890ea892013-03-15 17:06:52 -05001106 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001107 struct hci_cp_write_eir cp;
1108
Johan Hedberg504c8dc2012-02-23 13:30:41 +02001109 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001110 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +02001111
Johan Hedberg976eb202012-10-24 21:12:01 +03001112 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001113 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001114
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001115 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberg890ea892013-03-15 17:06:52 -05001116 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001117
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001118 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -05001119 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001120
1121 memset(&cp, 0, sizeof(cp));
1122
1123 create_eir(hdev, cp.data);
1124
1125 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -05001126 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001127
1128 memcpy(hdev->eir, cp.data, sizeof(cp.data));
1129
Johan Hedberg890ea892013-03-15 17:06:52 -05001130 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001131}
1132
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001133static u8 get_service_classes(struct hci_dev *hdev)
1134{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -03001135 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001136 u8 val = 0;
1137
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -03001138 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001139 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001140
1141 return val;
1142}
1143
Johan Hedberg890ea892013-03-15 17:06:52 -05001144static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001145{
Johan Hedberg890ea892013-03-15 17:06:52 -05001146 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001147 u8 cod[3];
1148
1149 BT_DBG("%s", hdev->name);
1150
Johan Hedberg504c8dc2012-02-23 13:30:41 +02001151 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05001152 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +02001153
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001154 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedbergf87ea1d2013-10-19 23:38:17 +03001155 return;
1156
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001157 if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg890ea892013-03-15 17:06:52 -05001158 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001159
1160 cod[0] = hdev->minor_class;
1161 cod[1] = hdev->major_class;
1162 cod[2] = get_service_classes(hdev);
1163
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001164 if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
Marcel Holtmann6acd7db2013-10-15 06:33:53 -07001165 cod[1] |= 0x20;
1166
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001167 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -05001168 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001169
Johan Hedberg890ea892013-03-15 17:06:52 -05001170 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001171}
1172
Johan Hedberga4858cb2014-02-25 19:56:31 +02001173static bool get_connectable(struct hci_dev *hdev)
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001174{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001175 struct mgmt_pending_cmd *cmd;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001176
1177 /* If there's a pending mgmt command the flag will not yet have
1178 * it's final value, so check for this first.
1179 */
1180 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1181 if (cmd) {
1182 struct mgmt_mode *cp = cmd->param;
Johan Hedberga4858cb2014-02-25 19:56:31 +02001183 return cp->val;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001184 }
1185
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001186 return hci_dev_test_flag(hdev, HCI_CONNECTABLE);
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001187}
1188
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001189static void disable_advertising(struct hci_request *req)
1190{
1191 u8 enable = 0x00;
1192
1193 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1194}
1195
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001196static void enable_advertising(struct hci_request *req)
1197{
1198 struct hci_dev *hdev = req->hdev;
1199 struct hci_cp_le_set_adv_param cp;
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001200 u8 own_addr_type, enable = 0x01;
Johan Hedberga4858cb2014-02-25 19:56:31 +02001201 bool connectable;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001202
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001203 if (hci_conn_num(hdev, LE_LINK) > 0)
1204 return;
1205
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001206 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03001207 disable_advertising(req);
1208
Johan Hedberg5ce194c2014-07-08 15:07:49 +03001209 /* Clear the HCI_LE_ADV bit temporarily so that the
Johan Hedberg8d972502014-02-28 12:54:14 +02001210 * hci_update_random_address knows that it's safe to go ahead
1211 * and write a new random address. The flag will be set back on
1212 * as soon as the SET_ADV_ENABLE HCI command completes.
1213 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001214 hci_dev_clear_flag(hdev, HCI_LE_ADV);
Johan Hedberg8d972502014-02-28 12:54:14 +02001215
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001216 if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE))
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07001217 connectable = true;
1218 else
1219 connectable = get_connectable(hdev);
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001220
Johan Hedberga4858cb2014-02-25 19:56:31 +02001221 /* Set require_privacy to true only when non-connectable
1222 * advertising is used. In that case it is fine to use a
1223 * non-resolvable private address.
1224 */
1225 if (hci_update_random_address(req, !connectable, &own_addr_type) < 0)
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001226 return;
1227
Marcel Holtmann41c90c12014-02-23 20:25:55 -08001228 memset(&cp, 0, sizeof(cp));
Georg Lukas628531c2014-07-26 13:59:57 +02001229 cp.min_interval = cpu_to_le16(hdev->le_adv_min_interval);
1230 cp.max_interval = cpu_to_le16(hdev->le_adv_max_interval);
Johan Hedberga4858cb2014-02-25 19:56:31 +02001231 cp.type = connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
Johan Hedberg8f2a0602014-02-23 19:42:23 +02001232 cp.own_address_type = own_addr_type;
Johan Hedberg199a2fb2014-02-22 19:06:33 +02001233 cp.channel_map = hdev->le_adv_channel_map;
1234
1235 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1236
1237 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1238}
1239
Johan Hedberg7d785252011-12-15 00:47:39 +02001240static void service_cache_off(struct work_struct *work)
1241{
1242 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001243 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -05001244 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +02001245
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001246 if (!hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE))
Johan Hedberg7d785252011-12-15 00:47:39 +02001247 return;
1248
Johan Hedberg890ea892013-03-15 17:06:52 -05001249 hci_req_init(&req, hdev);
1250
Johan Hedberg7d785252011-12-15 00:47:39 +02001251 hci_dev_lock(hdev);
1252
Johan Hedberg890ea892013-03-15 17:06:52 -05001253 update_eir(&req);
1254 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001255
1256 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001257
1258 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +02001259}
1260
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001261static void rpa_expired(struct work_struct *work)
1262{
1263 struct hci_dev *hdev = container_of(work, struct hci_dev,
1264 rpa_expired.work);
1265 struct hci_request req;
1266
1267 BT_DBG("");
1268
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001269 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001270
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001271 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001272 return;
1273
1274 /* The generation of a new RPA and programming it into the
1275 * controller happens in the enable_advertising() function.
1276 */
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001277 hci_req_init(&req, hdev);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001278 enable_advertising(&req);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001279 hci_req_run(&req, NULL);
1280}
1281
Johan Hedberg6a919082012-02-28 06:17:26 +02001282static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +02001283{
Marcel Holtmann238be782015-03-13 02:11:06 -07001284 if (hci_dev_test_and_set_flag(hdev, HCI_MGMT))
Johan Hedberg6a919082012-02-28 06:17:26 +02001285 return;
1286
Johan Hedberg4f87da82012-03-02 19:55:56 +02001287 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +02001288 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +02001289
Johan Hedberg4f87da82012-03-02 19:55:56 +02001290 /* Non-mgmt controlled devices get this bit set
1291 * implicitly so that pairing works for them, however
1292 * for mgmt we require user-space to explicitly enable
1293 * it
1294 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001295 hci_dev_clear_flag(hdev, HCI_BONDABLE);
Johan Hedberg7d785252011-12-15 00:47:39 +02001296}
1297
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001298static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001299 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +02001300{
1301 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +02001302
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001303 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001304
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001305 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001306
Johan Hedberg03811012010-12-08 00:21:06 +02001307 memset(&rp, 0, sizeof(rp));
1308
Johan Hedberg03811012010-12-08 00:21:06 +02001309 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001310
1311 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001312 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001313
1314 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
1315 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
1316
1317 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +02001318
1319 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +02001320 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +02001321
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001322 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001323
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001324 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
1325 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +02001326}
1327
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001328static void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
Johan Hedberg03811012010-12-08 00:21:06 +02001329{
1330 sock_put(cmd->sk);
1331 kfree(cmd->param);
1332 kfree(cmd);
1333}
1334
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001335static struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
1336 struct hci_dev *hdev,
1337 void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001338{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001339 struct mgmt_pending_cmd *cmd;
Johan Hedberg03811012010-12-08 00:21:06 +02001340
Johan Hedbergfca20012014-06-28 17:54:05 +03001341 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001342 if (!cmd)
1343 return NULL;
1344
1345 cmd->opcode = opcode;
1346 cmd->index = hdev->id;
1347
Johan Hedberg323b0b82014-12-05 13:36:01 +02001348 cmd->param = kmemdup(data, len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001349 if (!cmd->param) {
1350 kfree(cmd);
1351 return NULL;
1352 }
1353
Johan Hedberg323b0b82014-12-05 13:36:01 +02001354 cmd->param_len = len;
Johan Hedberg03811012010-12-08 00:21:06 +02001355
1356 cmd->sk = sk;
1357 sock_hold(sk);
1358
1359 list_add(&cmd->list, &hdev->mgmt_pending);
1360
1361 return cmd;
1362}
1363
1364static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001365 void (*cb)(struct mgmt_pending_cmd *cmd,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001366 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001367 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02001368{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001369 struct mgmt_pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +02001370
Andre Guedesa3d09352013-02-01 11:21:30 -03001371 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +02001372 if (opcode > 0 && cmd->opcode != opcode)
1373 continue;
1374
1375 cb(cmd, data);
1376 }
1377}
1378
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001379static void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
Johan Hedberg03811012010-12-08 00:21:06 +02001380{
1381 list_del(&cmd->list);
1382 mgmt_pending_free(cmd);
1383}
1384
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001385static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001386{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001387 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001388
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001389 return mgmt_cmd_complete(sk, hdev->id, opcode, 0, &settings,
1390 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001391}
1392
Marcel Holtmann1904a852015-01-11 13:50:44 -08001393static void clean_up_hci_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg8b064a32014-02-24 14:52:22 +02001394{
1395 BT_DBG("%s status 0x%02x", hdev->name, status);
1396
Johan Hedberga3172b72014-02-28 09:33:44 +02001397 if (hci_conn_count(hdev) == 0) {
1398 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001399 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberga3172b72014-02-28 09:33:44 +02001400 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001401}
1402
Johan Hedberg23a48092014-07-08 16:05:06 +03001403static bool hci_stop_discovery(struct hci_request *req)
Johan Hedberg21a60d32014-06-10 14:05:58 +03001404{
1405 struct hci_dev *hdev = req->hdev;
1406 struct hci_cp_remote_name_req_cancel cp;
1407 struct inquiry_entry *e;
1408
1409 switch (hdev->discovery.state) {
1410 case DISCOVERY_FINDING:
Jakub Pawlowski07d23342015-03-17 09:04:14 -07001411 if (test_bit(HCI_INQUIRY, &hdev->flags))
Johan Hedberg21a60d32014-06-10 14:05:58 +03001412 hci_req_add(req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
Jakub Pawlowski07d23342015-03-17 09:04:14 -07001413
1414 if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
Johan Hedberg21a60d32014-06-10 14:05:58 +03001415 cancel_delayed_work(&hdev->le_scan_disable);
1416 hci_req_add_le_scan_disable(req);
1417 }
1418
Johan Hedberg23a48092014-07-08 16:05:06 +03001419 return true;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001420
1421 case DISCOVERY_RESOLVING:
1422 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
1423 NAME_PENDING);
1424 if (!e)
Johan Hedberg23a48092014-07-08 16:05:06 +03001425 break;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001426
1427 bacpy(&cp.bdaddr, &e->data.bdaddr);
1428 hci_req_add(req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
1429 &cp);
1430
Johan Hedberg23a48092014-07-08 16:05:06 +03001431 return true;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001432
1433 default:
1434 /* Passive scanning */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001435 if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
Johan Hedberg21a60d32014-06-10 14:05:58 +03001436 hci_req_add_le_scan_disable(req);
Johan Hedberg23a48092014-07-08 16:05:06 +03001437 return true;
1438 }
1439
Johan Hedberg21a60d32014-06-10 14:05:58 +03001440 break;
1441 }
Johan Hedberg23a48092014-07-08 16:05:06 +03001442
1443 return false;
Johan Hedberg21a60d32014-06-10 14:05:58 +03001444}
1445
Johan Hedberg8b064a32014-02-24 14:52:22 +02001446static int clean_up_hci_state(struct hci_dev *hdev)
1447{
1448 struct hci_request req;
1449 struct hci_conn *conn;
Johan Hedberg23a48092014-07-08 16:05:06 +03001450 bool discov_stopped;
1451 int err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001452
1453 hci_req_init(&req, hdev);
1454
1455 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1456 test_bit(HCI_PSCAN, &hdev->flags)) {
1457 u8 scan = 0x00;
1458 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1459 }
1460
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001461 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Johan Hedberg8b064a32014-02-24 14:52:22 +02001462 disable_advertising(&req);
1463
Johan Hedberg23a48092014-07-08 16:05:06 +03001464 discov_stopped = hci_stop_discovery(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001465
1466 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
1467 struct hci_cp_disconnect dc;
Johan Hedbergc9910d02014-02-27 14:35:12 +02001468 struct hci_cp_reject_conn_req rej;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001469
Johan Hedbergc9910d02014-02-27 14:35:12 +02001470 switch (conn->state) {
1471 case BT_CONNECTED:
1472 case BT_CONFIG:
1473 dc.handle = cpu_to_le16(conn->handle);
1474 dc.reason = 0x15; /* Terminated due to Power Off */
1475 hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1476 break;
1477 case BT_CONNECT:
1478 if (conn->type == LE_LINK)
1479 hci_req_add(&req, HCI_OP_LE_CREATE_CONN_CANCEL,
1480 0, NULL);
1481 else if (conn->type == ACL_LINK)
1482 hci_req_add(&req, HCI_OP_CREATE_CONN_CANCEL,
1483 6, &conn->dst);
1484 break;
1485 case BT_CONNECT2:
1486 bacpy(&rej.bdaddr, &conn->dst);
1487 rej.reason = 0x15; /* Terminated due to Power Off */
1488 if (conn->type == ACL_LINK)
1489 hci_req_add(&req, HCI_OP_REJECT_CONN_REQ,
1490 sizeof(rej), &rej);
1491 else if (conn->type == SCO_LINK)
1492 hci_req_add(&req, HCI_OP_REJECT_SYNC_CONN_REQ,
1493 sizeof(rej), &rej);
1494 break;
1495 }
Johan Hedberg8b064a32014-02-24 14:52:22 +02001496 }
1497
Johan Hedberg23a48092014-07-08 16:05:06 +03001498 err = hci_req_run(&req, clean_up_hci_complete);
1499 if (!err && discov_stopped)
1500 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1501
1502 return err;
Johan Hedberg8b064a32014-02-24 14:52:22 +02001503}
1504
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001505static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001506 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001507{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001508 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001509 struct mgmt_pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001510 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001511
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001512 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001513
Johan Hedberga7e80f22013-01-09 16:05:19 +02001514 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02001515 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1516 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001517
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001518 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001519
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001520 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001521 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1522 MGMT_STATUS_BUSY);
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001523 goto failed;
1524 }
1525
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001526 if (hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF)) {
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001527 cancel_delayed_work(&hdev->power_off);
1528
1529 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +02001530 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
1531 data, len);
1532 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001533 goto failed;
1534 }
1535 }
1536
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001537 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001538 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001539 goto failed;
1540 }
1541
Johan Hedberg03811012010-12-08 00:21:06 +02001542 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1543 if (!cmd) {
1544 err = -ENOMEM;
1545 goto failed;
1546 }
1547
Johan Hedberg8b064a32014-02-24 14:52:22 +02001548 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001549 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001550 err = 0;
1551 } else {
1552 /* Disconnect connections, stop scans, etc */
1553 err = clean_up_hci_state(hdev);
Johan Hedberga3172b72014-02-28 09:33:44 +02001554 if (!err)
1555 queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
1556 HCI_POWER_OFF_TIMEOUT);
Johan Hedberg03811012010-12-08 00:21:06 +02001557
Johan Hedberg8b064a32014-02-24 14:52:22 +02001558 /* ENODATA means there were no HCI commands queued */
1559 if (err == -ENODATA) {
Johan Hedberga3172b72014-02-28 09:33:44 +02001560 cancel_delayed_work(&hdev->power_off);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001561 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1562 err = 0;
1563 }
1564 }
Johan Hedberg03811012010-12-08 00:21:06 +02001565
1566failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001567 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001568 return err;
1569}
1570
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001571static int new_settings(struct hci_dev *hdev, struct sock *skip)
1572{
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001573 __le32 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001574
Marcel Holtmannf6b77122015-03-14 19:28:05 -07001575 return mgmt_generic_event(MGMT_EV_NEW_SETTINGS, hdev, &ev,
1576 sizeof(ev), skip);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001577}
1578
Johan Hedberg91a668b2014-07-09 13:28:26 +03001579int mgmt_new_settings(struct hci_dev *hdev)
1580{
1581 return new_settings(hdev, NULL);
1582}
1583
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001584struct cmd_lookup {
1585 struct sock *sk;
1586 struct hci_dev *hdev;
1587 u8 mgmt_status;
1588};
1589
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001590static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001591{
1592 struct cmd_lookup *match = data;
1593
1594 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1595
1596 list_del(&cmd->list);
1597
1598 if (match->sk == NULL) {
1599 match->sk = cmd->sk;
1600 sock_hold(match->sk);
1601 }
1602
1603 mgmt_pending_free(cmd);
1604}
1605
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001606static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001607{
1608 u8 *status = data;
1609
Johan Hedberga69e8372015-03-06 21:08:53 +02001610 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001611 mgmt_pending_remove(cmd);
1612}
1613
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001614static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg1b9b5ee2014-12-05 13:36:00 +02001615{
1616 if (cmd->cmd_complete) {
1617 u8 *status = data;
1618
1619 cmd->cmd_complete(cmd, *status);
1620 mgmt_pending_remove(cmd);
1621
1622 return;
1623 }
1624
1625 cmd_status_rsp(cmd, data);
1626}
1627
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001628static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedbergf5818c22014-12-05 13:36:02 +02001629{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001630 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1631 cmd->param, cmd->param_len);
Johan Hedbergf5818c22014-12-05 13:36:02 +02001632}
1633
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001634static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001635{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02001636 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
1637 cmd->param, sizeof(struct mgmt_addr_info));
Johan Hedberg7776d1d2014-12-05 13:36:03 +02001638}
1639
Johan Hedberge6fe7982013-10-02 15:45:22 +03001640static u8 mgmt_bredr_support(struct hci_dev *hdev)
1641{
1642 if (!lmp_bredr_capable(hdev))
1643 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001644 else if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001645 return MGMT_STATUS_REJECTED;
1646 else
1647 return MGMT_STATUS_SUCCESS;
1648}
1649
1650static u8 mgmt_le_support(struct hci_dev *hdev)
1651{
1652 if (!lmp_le_capable(hdev))
1653 return MGMT_STATUS_NOT_SUPPORTED;
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001654 else if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberge6fe7982013-10-02 15:45:22 +03001655 return MGMT_STATUS_REJECTED;
1656 else
1657 return MGMT_STATUS_SUCCESS;
1658}
1659
Marcel Holtmann1904a852015-01-11 13:50:44 -08001660static void set_discoverable_complete(struct hci_dev *hdev, u8 status,
1661 u16 opcode)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001662{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001663 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001664 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001665 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001666 bool changed;
1667
1668 BT_DBG("status 0x%02x", status);
1669
1670 hci_dev_lock(hdev);
1671
1672 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1673 if (!cmd)
1674 goto unlock;
1675
1676 if (status) {
1677 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001678 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001679 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001680 goto remove_cmd;
1681 }
1682
1683 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001684 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001685 changed = !hci_dev_test_and_set_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001686
1687 if (hdev->discov_timeout > 0) {
1688 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1689 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1690 to);
1691 }
1692 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001693 changed = hci_dev_test_and_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001694 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001695
1696 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1697
1698 if (changed)
1699 new_settings(hdev, cmd->sk);
1700
Marcel Holtmann970ba522013-10-15 06:33:57 -07001701 /* When the discoverable mode gets changed, make sure
1702 * that class of device has the limited discoverable
Johan Hedberg432df052014-08-01 11:13:31 +03001703 * bit correctly set. Also update page scan based on whitelist
1704 * entries.
Marcel Holtmann970ba522013-10-15 06:33:57 -07001705 */
1706 hci_req_init(&req, hdev);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001707 __hci_update_page_scan(&req);
Marcel Holtmann970ba522013-10-15 06:33:57 -07001708 update_class(&req);
1709 hci_req_run(&req, NULL);
1710
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001711remove_cmd:
1712 mgmt_pending_remove(cmd);
1713
1714unlock:
1715 hci_dev_unlock(hdev);
1716}
1717
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001718static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001719 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001720{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001721 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001722 struct mgmt_pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001723 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001724 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001725 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001726 int err;
Johan Hedberge41d8b42010-12-13 21:07:03 +02001727
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001728 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001729
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001730 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
1731 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02001732 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1733 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001734
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001735 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02001736 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1737 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02001738
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001739 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001740
1741 /* Disabling discoverable requires that no timeout is set,
1742 * and enabling limited discoverable requires a timeout.
1743 */
1744 if ((cp->val == 0x00 && timeout > 0) ||
1745 (cp->val == 0x02 && timeout == 0))
Johan Hedberga69e8372015-03-06 21:08:53 +02001746 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1747 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001748
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001749 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001750
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001751 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001752 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1753 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001754 goto failed;
1755 }
1756
1757 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001758 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001759 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1760 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001761 goto failed;
1762 }
1763
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001764 if (!hci_dev_test_flag(hdev, HCI_CONNECTABLE)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02001765 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1766 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001767 goto failed;
1768 }
1769
1770 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001771 bool changed = false;
1772
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001773 /* Setting limited discoverable when powered off is
1774 * not a valid operation since it requires a timeout
1775 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1776 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001777 if (!!cp->val != hci_dev_test_flag(hdev, HCI_DISCOVERABLE)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07001778 hci_dev_change_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001779 changed = true;
1780 }
1781
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001782 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001783 if (err < 0)
1784 goto failed;
1785
1786 if (changed)
1787 err = new_settings(hdev, sk);
1788
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001789 goto failed;
1790 }
1791
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001792 /* If the current mode is the same, then just update the timeout
1793 * value with the new value. And if only the timeout gets updated,
1794 * then no need for any HCI transactions.
1795 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001796 if (!!cp->val == hci_dev_test_flag(hdev, HCI_DISCOVERABLE) &&
1797 (cp->val == 0x02) == hci_dev_test_flag(hdev,
1798 HCI_LIMITED_DISCOVERABLE)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001799 cancel_delayed_work(&hdev->discov_off);
1800 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001801
Marcel Holtmann36261542013-10-15 08:28:51 -07001802 if (cp->val && hdev->discov_timeout > 0) {
1803 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001804 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001805 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001806 }
1807
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001808 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001809 goto failed;
1810 }
1811
1812 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1813 if (!cmd) {
1814 err = -ENOMEM;
1815 goto failed;
1816 }
1817
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001818 /* Cancel any potential discoverable timeout that might be
1819 * still active and store new timeout value. The arming of
1820 * the timeout happens in the complete handler.
1821 */
1822 cancel_delayed_work(&hdev->discov_off);
1823 hdev->discov_timeout = timeout;
1824
Johan Hedbergb456f872013-10-19 23:38:22 +03001825 /* Limited discoverable mode */
1826 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001827 hci_dev_set_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001828 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001829 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Johan Hedbergb456f872013-10-19 23:38:22 +03001830
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001831 hci_req_init(&req, hdev);
1832
Johan Hedberg9a43e252013-10-20 19:00:07 +03001833 /* The procedure for LE-only controllers is much simpler - just
1834 * update the advertising data.
1835 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001836 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg9a43e252013-10-20 19:00:07 +03001837 goto update_ad;
1838
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001839 scan = SCAN_PAGE;
1840
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001841 if (cp->val) {
1842 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001843
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001844 if (cp->val == 0x02) {
1845 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001846 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001847 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1848 hci_cp.iac_lap[1] = 0x8b;
1849 hci_cp.iac_lap[2] = 0x9e;
1850 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1851 hci_cp.iac_lap[4] = 0x8b;
1852 hci_cp.iac_lap[5] = 0x9e;
1853 } else {
1854 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001855 hci_cp.num_iac = 1;
1856 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1857 hci_cp.iac_lap[1] = 0x8b;
1858 hci_cp.iac_lap[2] = 0x9e;
1859 }
1860
1861 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1862 (hci_cp.num_iac * 3) + 1, &hci_cp);
1863
1864 scan |= SCAN_INQUIRY;
1865 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001866 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001867 }
1868
1869 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001870
Johan Hedberg9a43e252013-10-20 19:00:07 +03001871update_ad:
1872 update_adv_data(&req);
1873
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001874 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001875 if (err < 0)
1876 mgmt_pending_remove(cmd);
1877
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001878failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001879 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001880 return err;
1881}
1882
Johan Hedberg406d7802013-03-15 17:07:09 -05001883static void write_fast_connectable(struct hci_request *req, bool enable)
1884{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001885 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001886 struct hci_cp_write_page_scan_activity acp;
1887 u8 type;
1888
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001889 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberg547003b2013-10-21 16:51:53 +03001890 return;
1891
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001892 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1893 return;
1894
Johan Hedberg406d7802013-03-15 17:07:09 -05001895 if (enable) {
1896 type = PAGE_SCAN_TYPE_INTERLACED;
1897
1898 /* 160 msec page scan interval */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001899 acp.interval = cpu_to_le16(0x0100);
Johan Hedberg406d7802013-03-15 17:07:09 -05001900 } else {
1901 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1902
1903 /* default 1.28 sec page scan */
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001904 acp.interval = cpu_to_le16(0x0800);
Johan Hedberg406d7802013-03-15 17:07:09 -05001905 }
1906
Joe Perchesdcf4adb2014-03-12 10:52:35 -07001907 acp.window = cpu_to_le16(0x0012);
Johan Hedberg406d7802013-03-15 17:07:09 -05001908
Johan Hedbergbd98b992013-03-15 17:07:13 -05001909 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1910 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1911 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1912 sizeof(acp), &acp);
1913
1914 if (hdev->page_scan_type != type)
1915 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001916}
1917
Marcel Holtmann1904a852015-01-11 13:50:44 -08001918static void set_connectable_complete(struct hci_dev *hdev, u8 status,
1919 u16 opcode)
Johan Hedberg2b76f452013-03-15 17:07:04 -05001920{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02001921 struct mgmt_pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001922 struct mgmt_mode *cp;
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001923 bool conn_changed, discov_changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001924
1925 BT_DBG("status 0x%02x", status);
1926
1927 hci_dev_lock(hdev);
1928
1929 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1930 if (!cmd)
1931 goto unlock;
1932
Johan Hedberg37438c12013-10-14 16:20:05 +03001933 if (status) {
1934 u8 mgmt_err = mgmt_status(status);
Johan Hedberga69e8372015-03-06 21:08:53 +02001935 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg37438c12013-10-14 16:20:05 +03001936 goto remove_cmd;
1937 }
1938
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001939 cp = cmd->param;
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001940 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07001941 conn_changed = !hci_dev_test_and_set_flag(hdev,
1942 HCI_CONNECTABLE);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001943 discov_changed = false;
1944 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07001945 conn_changed = hci_dev_test_and_clear_flag(hdev,
1946 HCI_CONNECTABLE);
1947 discov_changed = hci_dev_test_and_clear_flag(hdev,
1948 HCI_DISCOVERABLE);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001949 }
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001950
Johan Hedberg2b76f452013-03-15 17:07:04 -05001951 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1952
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001953 if (conn_changed || discov_changed) {
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001954 new_settings(hdev, cmd->sk);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001955 hci_update_page_scan(hdev);
Johan Hedbergbc6d2d02014-07-10 12:09:08 +03001956 if (discov_changed)
1957 mgmt_update_adv_data(hdev);
Johan Hedberg2b7be332014-07-07 14:40:22 +03001958 hci_update_background_scan(hdev);
1959 }
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001960
Johan Hedberg37438c12013-10-14 16:20:05 +03001961remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001962 mgmt_pending_remove(cmd);
1963
1964unlock:
1965 hci_dev_unlock(hdev);
1966}
1967
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001968static int set_connectable_update_settings(struct hci_dev *hdev,
1969 struct sock *sk, u8 val)
1970{
1971 bool changed = false;
1972 int err;
1973
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07001974 if (!!val != hci_dev_test_flag(hdev, HCI_CONNECTABLE))
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001975 changed = true;
1976
1977 if (val) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07001978 hci_dev_set_flag(hdev, HCI_CONNECTABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001979 } else {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07001980 hci_dev_clear_flag(hdev, HCI_CONNECTABLE);
1981 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001982 }
1983
1984 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1985 if (err < 0)
1986 return err;
1987
Johan Hedberg562064e2014-07-08 16:35:34 +03001988 if (changed) {
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02001989 hci_update_page_scan(hdev);
Johan Hedberg562064e2014-07-08 16:35:34 +03001990 hci_update_background_scan(hdev);
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001991 return new_settings(hdev, sk);
Johan Hedberg562064e2014-07-08 16:35:34 +03001992 }
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001993
1994 return 0;
1995}
1996
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001997static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001998 u16 len)
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001999{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002000 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002001 struct mgmt_pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05002002 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03002003 u8 scan;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002004 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002005
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002006 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002007
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002008 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
2009 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02002010 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
2011 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03002012
Johan Hedberga7e80f22013-01-09 16:05:19 +02002013 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002014 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
2015 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002016
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002017 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002018
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002019 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03002020 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002021 goto failed;
2022 }
2023
2024 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002025 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002026 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
2027 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002028 goto failed;
2029 }
2030
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002031 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
2032 if (!cmd) {
2033 err = -ENOMEM;
2034 goto failed;
2035 }
2036
Johan Hedberg2b76f452013-03-15 17:07:04 -05002037 hci_req_init(&req, hdev);
2038
Johan Hedberg9a43e252013-10-20 19:00:07 +03002039 /* If BR/EDR is not enabled and we disable advertising as a
2040 * by-product of disabling connectable, we need to update the
2041 * advertising flags.
2042 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002043 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg9a43e252013-10-20 19:00:07 +03002044 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002045 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
2046 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Johan Hedberg9a43e252013-10-20 19:00:07 +03002047 }
2048 update_adv_data(&req);
2049 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03002050 if (cp->val) {
2051 scan = SCAN_PAGE;
2052 } else {
Johan Hedberg3bd27242014-07-28 20:53:58 +03002053 /* If we don't have any whitelist entries just
2054 * disable all scanning. If there are entries
2055 * and we had both page and inquiry scanning
2056 * enabled then fall back to only page scanning.
2057 * Otherwise no changes are needed.
2058 */
2059 if (list_empty(&hdev->whitelist))
2060 scan = SCAN_DISABLED;
2061 else if (test_bit(HCI_ISCAN, &hdev->flags))
2062 scan = SCAN_PAGE;
2063 else
2064 goto no_scan_update;
Johan Hedberg9b742462013-10-14 16:20:03 +03002065
2066 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07002067 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03002068 cancel_delayed_work(&hdev->discov_off);
2069 }
2070
2071 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
2072 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05002073
Johan Hedberg3bd27242014-07-28 20:53:58 +03002074no_scan_update:
Johan Hedberge8b12022014-07-10 10:51:27 +03002075 /* Update the advertising parameters if necessary */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002076 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Johan Hedberg1987fdc2013-10-14 21:15:24 +03002077 enable_advertising(&req);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03002078
Johan Hedberg2b76f452013-03-15 17:07:04 -05002079 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03002080 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002081 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03002082 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03002083 err = set_connectable_update_settings(hdev, sk,
2084 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03002085 goto failed;
2086 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002087
2088failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002089 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002090 return err;
2091}
2092
Johan Hedbergb2939472014-07-30 09:22:23 +03002093static int set_bondable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002094 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002095{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002096 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07002097 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002098 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002099
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002100 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002101
Johan Hedberga7e80f22013-01-09 16:05:19 +02002102 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002103 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BONDABLE,
2104 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002105
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002106 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002107
2108 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07002109 changed = !hci_dev_test_and_set_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002110 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002111 changed = hci_dev_test_and_clear_flag(hdev, HCI_BONDABLE);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002112
Johan Hedbergb2939472014-07-30 09:22:23 +03002113 err = send_settings_rsp(sk, MGMT_OP_SET_BONDABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002114 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07002115 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002116
Marcel Holtmann55594352013-10-06 16:11:57 -07002117 if (changed)
2118 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002119
Marcel Holtmann55594352013-10-06 16:11:57 -07002120unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002121 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002122 return err;
2123}
Johan Hedberg72a734e2010-12-30 00:38:22 +02002124
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002125static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
2126 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002127{
2128 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002129 struct mgmt_pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03002130 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002131 int err;
2132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002133 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002134
Johan Hedberge6fe7982013-10-02 15:45:22 +03002135 status = mgmt_bredr_support(hdev);
2136 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002137 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2138 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03002139
Johan Hedberga7e80f22013-01-09 16:05:19 +02002140 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002141 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2142 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002143
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002144 hci_dev_lock(hdev);
2145
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002146 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02002147 bool changed = false;
2148
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002149 if (!!cp->val != hci_dev_test_flag(hdev, HCI_LINK_SECURITY)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07002150 hci_dev_change_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02002151 changed = true;
2152 }
2153
2154 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
2155 if (err < 0)
2156 goto failed;
2157
2158 if (changed)
2159 err = new_settings(hdev, sk);
2160
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002161 goto failed;
2162 }
2163
2164 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002165 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
2166 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002167 goto failed;
2168 }
2169
2170 val = !!cp->val;
2171
2172 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
2173 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
2174 goto failed;
2175 }
2176
2177 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
2178 if (!cmd) {
2179 err = -ENOMEM;
2180 goto failed;
2181 }
2182
2183 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
2184 if (err < 0) {
2185 mgmt_pending_remove(cmd);
2186 goto failed;
2187 }
2188
2189failed:
2190 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002191 return err;
2192}
2193
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002194static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002195{
2196 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002197 struct mgmt_pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07002198 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002199 int err;
2200
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002201 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002202
Marcel Holtmanncdba5282013-10-02 21:31:52 -07002203 status = mgmt_bredr_support(hdev);
2204 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002205 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
Marcel Holtmanncdba5282013-10-02 21:31:52 -07002206
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002207 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002208 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2209 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002210
Johan Hedberga7e80f22013-01-09 16:05:19 +02002211 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002212 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2213 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002214
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002215 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02002216
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002217 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002218 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02002219
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002220 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07002221 changed = !hci_dev_test_and_set_flag(hdev,
2222 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002223 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002224 changed = hci_dev_test_and_clear_flag(hdev,
2225 HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002226 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002227 changed = hci_dev_test_and_clear_flag(hdev,
2228 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002229 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002230 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02002231 }
2232
2233 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
2234 if (err < 0)
2235 goto failed;
2236
2237 if (changed)
2238 err = new_settings(hdev, sk);
2239
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002240 goto failed;
2241 }
2242
Johan Hedberg94d52da2015-02-19 17:38:06 +02002243 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002244 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
2245 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002246 goto failed;
2247 }
2248
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002249 if (!!cp->val == hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002250 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
2251 goto failed;
2252 }
2253
2254 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
2255 if (!cmd) {
2256 err = -ENOMEM;
2257 goto failed;
2258 }
2259
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002260 if (!cp->val && hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03002261 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
2262 sizeof(cp->val), &cp->val);
2263
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07002264 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002265 if (err < 0) {
2266 mgmt_pending_remove(cmd);
2267 goto failed;
2268 }
2269
2270failed:
2271 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002272 return err;
2273}
2274
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002275static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002276{
2277 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07002278 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03002279 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07002280 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002281
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002282 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002283
Johan Hedberge6fe7982013-10-02 15:45:22 +03002284 status = mgmt_bredr_support(hdev);
2285 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02002286 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002287
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002288 if (!lmp_ssp_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002289 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2290 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002291
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002292 if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02002293 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2294 MGMT_STATUS_REJECTED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07002295
Johan Hedberga7e80f22013-01-09 16:05:19 +02002296 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002297 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2298 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002299
Marcel Holtmannee392692013-10-01 22:59:23 -07002300 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002301
Johan Hedberga2cb01d2015-02-19 17:38:07 +02002302 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002303 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2304 MGMT_STATUS_BUSY);
Johan Hedberga2cb01d2015-02-19 17:38:07 +02002305 goto unlock;
2306 }
2307
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002308 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07002309 changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002310 } else {
2311 if (hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002312 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
2313 MGMT_STATUS_REJECTED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002314 goto unlock;
2315 }
2316
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002317 changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07002318 }
Marcel Holtmannee392692013-10-01 22:59:23 -07002319
2320 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
2321 if (err < 0)
2322 goto unlock;
2323
2324 if (changed)
2325 err = new_settings(hdev, sk);
2326
2327unlock:
2328 hci_dev_unlock(hdev);
2329 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002330}
2331
Marcel Holtmann1904a852015-01-11 13:50:44 -08002332static void le_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002333{
2334 struct cmd_lookup match = { NULL, hdev };
2335
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302336 hci_dev_lock(hdev);
2337
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002338 if (status) {
2339 u8 mgmt_err = mgmt_status(status);
2340
2341 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
2342 &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302343 goto unlock;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002344 }
2345
2346 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
2347
2348 new_settings(hdev, match.sk);
2349
2350 if (match.sk)
2351 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002352
2353 /* Make sure the controller has a good default for
2354 * advertising data. Restrict the update to when LE
2355 * has actually been enabled. During power on, the
2356 * update in powered_update_hci will take care of it.
2357 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002358 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002359 struct hci_request req;
2360
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002361 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07002362 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07002363 update_scan_rsp_data(&req);
Johan Hedberg2cf22212014-12-19 22:26:00 +02002364 __hci_update_background_scan(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002365 hci_req_run(&req, NULL);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002366 }
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05302367
2368unlock:
2369 hci_dev_unlock(hdev);
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002370}
2371
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002372static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002373{
2374 struct mgmt_mode *cp = data;
2375 struct hci_cp_write_le_host_supported hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002376 struct mgmt_pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002377 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002378 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002379 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002380
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002381 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002382
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002383 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002384 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2385 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002386
Johan Hedberga7e80f22013-01-09 16:05:19 +02002387 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002388 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2389 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02002390
Johan Hedbergc73eee92013-04-19 18:35:21 +03002391 /* LE-only devices do not allow toggling LE on/off */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002392 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02002393 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2394 MGMT_STATUS_REJECTED);
Johan Hedbergc73eee92013-04-19 18:35:21 +03002395
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002396 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002397
2398 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02002399 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002400
Johan Hedberg0b60eba2012-02-28 00:57:24 +02002401 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02002402 bool changed = false;
2403
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002404 if (val != hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07002405 hci_dev_change_flag(hdev, HCI_LE_ENABLED);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002406 changed = true;
2407 }
2408
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002409 if (!val && hci_dev_test_flag(hdev, HCI_ADVERTISING)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07002410 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03002411 changed = true;
2412 }
2413
Johan Hedberg06199cf2012-02-22 16:37:11 +02002414 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
2415 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08002416 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002417
2418 if (changed)
2419 err = new_settings(hdev, sk);
2420
Johan Hedberg1de028c2012-02-29 19:55:35 -08002421 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002422 }
2423
Johan Hedberg4375f102013-09-25 13:26:10 +03002424 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
2425 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002426 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
2427 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08002428 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002429 }
2430
2431 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
2432 if (!cmd) {
2433 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08002434 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002435 }
2436
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002437 hci_req_init(&req, hdev);
2438
Johan Hedberg06199cf2012-02-22 16:37:11 +02002439 memset(&hci_cp, 0, sizeof(hci_cp));
2440
2441 if (val) {
2442 hci_cp.le = val;
Marcel Holtmann32226e42014-07-24 20:04:16 +02002443 hci_cp.simul = 0x00;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002444 } else {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07002445 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002446 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002447 }
2448
Johan Hedberg416a4ae2013-09-25 13:26:08 +03002449 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
2450 &hci_cp);
2451
2452 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05302453 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02002454 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002455
Johan Hedberg1de028c2012-02-29 19:55:35 -08002456unlock:
2457 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02002458 return err;
2459}
2460
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002461/* This is a helper function to test for pending mgmt commands that can
2462 * cause CoD or EIR HCI commands. We can only allow one such pending
2463 * mgmt command at a time since otherwise we cannot easily track what
2464 * the current values are, will be, and based on that calculate if a new
2465 * HCI command needs to be sent and if yes with what value.
2466 */
2467static bool pending_eir_or_class(struct hci_dev *hdev)
2468{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002469 struct mgmt_pending_cmd *cmd;
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002470
2471 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2472 switch (cmd->opcode) {
2473 case MGMT_OP_ADD_UUID:
2474 case MGMT_OP_REMOVE_UUID:
2475 case MGMT_OP_SET_DEV_CLASS:
2476 case MGMT_OP_SET_POWERED:
2477 return true;
2478 }
2479 }
2480
2481 return false;
2482}
2483
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002484static const u8 bluetooth_base_uuid[] = {
2485 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2486 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2487};
2488
2489static u8 get_uuid_size(const u8 *uuid)
2490{
2491 u32 val;
2492
2493 if (memcmp(uuid, bluetooth_base_uuid, 12))
2494 return 128;
2495
2496 val = get_unaligned_le32(&uuid[12]);
2497 if (val > 0xffff)
2498 return 32;
2499
2500 return 16;
2501}
2502
Johan Hedberg92da6092013-03-15 17:06:55 -05002503static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2504{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002505 struct mgmt_pending_cmd *cmd;
Johan Hedberg92da6092013-03-15 17:06:55 -05002506
2507 hci_dev_lock(hdev);
2508
2509 cmd = mgmt_pending_find(mgmt_op, hdev);
2510 if (!cmd)
2511 goto unlock;
2512
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002513 mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
2514 mgmt_status(status), hdev->dev_class, 3);
Johan Hedberg92da6092013-03-15 17:06:55 -05002515
2516 mgmt_pending_remove(cmd);
2517
2518unlock:
2519 hci_dev_unlock(hdev);
2520}
2521
Marcel Holtmann1904a852015-01-11 13:50:44 -08002522static void add_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002523{
2524 BT_DBG("status 0x%02x", status);
2525
2526 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2527}
2528
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002529static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002530{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002531 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002532 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002533 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002534 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002535 int err;
2536
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002537 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002538
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002539 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002540
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002541 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002542 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
2543 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002544 goto failed;
2545 }
2546
Andre Guedes92c4c202012-06-07 19:05:44 -03002547 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002548 if (!uuid) {
2549 err = -ENOMEM;
2550 goto failed;
2551 }
2552
2553 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002554 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002555 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002556
Johan Hedbergde66aa62013-01-27 00:31:27 +02002557 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002558
Johan Hedberg890ea892013-03-15 17:06:52 -05002559 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002560
Johan Hedberg890ea892013-03-15 17:06:52 -05002561 update_class(&req);
2562 update_eir(&req);
2563
Johan Hedberg92da6092013-03-15 17:06:55 -05002564 err = hci_req_run(&req, add_uuid_complete);
2565 if (err < 0) {
2566 if (err != -ENODATA)
2567 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002568
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002569 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
2570 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002571 goto failed;
2572 }
2573
2574 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002575 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002576 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002577 goto failed;
2578 }
2579
2580 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002581
2582failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002583 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002584 return err;
2585}
2586
Johan Hedberg24b78d02012-02-23 23:24:30 +02002587static bool enable_service_cache(struct hci_dev *hdev)
2588{
2589 if (!hdev_is_powered(hdev))
2590 return false;
2591
Marcel Holtmann238be782015-03-13 02:11:06 -07002592 if (!hci_dev_test_and_set_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002593 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2594 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002595 return true;
2596 }
2597
2598 return false;
2599}
2600
Marcel Holtmann1904a852015-01-11 13:50:44 -08002601static void remove_uuid_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002602{
2603 BT_DBG("status 0x%02x", status);
2604
2605 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2606}
2607
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002608static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002609 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002610{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002611 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002612 struct mgmt_pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002613 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002614 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 -05002615 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002616 int err, found;
2617
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002618 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002619
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002620 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002621
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002622 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002623 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2624 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002625 goto unlock;
2626 }
2627
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002628 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002629 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002630
Johan Hedberg24b78d02012-02-23 23:24:30 +02002631 if (enable_service_cache(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002632 err = mgmt_cmd_complete(sk, hdev->id,
2633 MGMT_OP_REMOVE_UUID,
2634 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002635 goto unlock;
2636 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002637
Johan Hedberg9246a862012-02-23 21:33:16 +02002638 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002639 }
2640
2641 found = 0;
2642
Johan Hedberg056341c2013-01-27 00:31:30 +02002643 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002644 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2645 continue;
2646
2647 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002648 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002649 found++;
2650 }
2651
2652 if (found == 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002653 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
2654 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002655 goto unlock;
2656 }
2657
Johan Hedberg9246a862012-02-23 21:33:16 +02002658update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002659 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002660
Johan Hedberg890ea892013-03-15 17:06:52 -05002661 update_class(&req);
2662 update_eir(&req);
2663
Johan Hedberg92da6092013-03-15 17:06:55 -05002664 err = hci_req_run(&req, remove_uuid_complete);
2665 if (err < 0) {
2666 if (err != -ENODATA)
2667 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002668
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002669 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
2670 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002671 goto unlock;
2672 }
2673
2674 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002675 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002676 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002677 goto unlock;
2678 }
2679
2680 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002681
2682unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002683 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002684 return err;
2685}
2686
Marcel Holtmann1904a852015-01-11 13:50:44 -08002687static void set_class_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg92da6092013-03-15 17:06:55 -05002688{
2689 BT_DBG("status 0x%02x", status);
2690
2691 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2692}
2693
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002694static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002695 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002696{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002697 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002698 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002699 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002700 int err;
2701
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002702 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002703
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002704 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002705 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2706 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002707
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002708 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002709
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002710 if (pending_eir_or_class(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002711 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2712 MGMT_STATUS_BUSY);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002713 goto unlock;
2714 }
2715
2716 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02002717 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2718 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002719 goto unlock;
2720 }
2721
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002722 hdev->major_class = cp->major;
2723 hdev->minor_class = cp->minor;
2724
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002725 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002726 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2727 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002728 goto unlock;
2729 }
2730
Johan Hedberg890ea892013-03-15 17:06:52 -05002731 hci_req_init(&req, hdev);
2732
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002733 if (hci_dev_test_and_clear_flag(hdev, HCI_SERVICE_CACHE)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002734 hci_dev_unlock(hdev);
2735 cancel_delayed_work_sync(&hdev->service_cache);
2736 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002737 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002738 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002739
Johan Hedberg890ea892013-03-15 17:06:52 -05002740 update_class(&req);
2741
Johan Hedberg92da6092013-03-15 17:06:55 -05002742 err = hci_req_run(&req, set_class_complete);
2743 if (err < 0) {
2744 if (err != -ENODATA)
2745 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002746
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002747 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
2748 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002749 goto unlock;
2750 }
2751
2752 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002753 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002754 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002755 goto unlock;
2756 }
2757
2758 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002759
Johan Hedbergb5235a62012-02-21 14:32:24 +02002760unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002761 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002762 return err;
2763}
2764
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002765static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002766 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002767{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002768 struct mgmt_cp_load_link_keys *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03002769 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
2770 sizeof(struct mgmt_link_key_info));
Szymon Janc4e51eae2011-02-25 19:05:48 +01002771 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002772 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002773 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002774
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002775 BT_DBG("request for %s", hdev->name);
2776
2777 if (!lmp_bredr_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02002778 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2779 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002780
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002781 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002782 if (key_count > max_key_count) {
2783 BT_ERR("load_link_keys: too big key_count value %u",
2784 key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02002785 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2786 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03002787 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002788
Johan Hedberg86742e12011-11-07 23:13:38 +02002789 expected_len = sizeof(*cp) + key_count *
2790 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002791 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002792 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02002793 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02002794 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2795 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002796 }
2797
Johan Hedberg4ae14302013-01-20 14:27:13 +02002798 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02002799 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2800 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ae14302013-01-20 14:27:13 +02002801
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002802 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002803 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002804
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002805 for (i = 0; i < key_count; i++) {
2806 struct mgmt_link_key_info *key = &cp->keys[i];
2807
Marcel Holtmann8e991132014-01-10 02:07:25 -08002808 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberga69e8372015-03-06 21:08:53 +02002809 return mgmt_cmd_status(sk, hdev->id,
2810 MGMT_OP_LOAD_LINK_KEYS,
2811 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002812 }
2813
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002814 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002815
2816 hci_link_keys_clear(hdev);
2817
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002818 if (cp->debug_keys)
Marcel Holtmann238be782015-03-13 02:11:06 -07002819 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002820 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07002821 changed = hci_dev_test_and_clear_flag(hdev,
2822 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002823
2824 if (changed)
2825 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002826
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002827 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002828 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002829
Johan Hedberg58e92932014-06-24 14:00:26 +03002830 /* Always ignore debug keys and require a new pairing if
2831 * the user wants to use them.
2832 */
2833 if (key->type == HCI_LK_DEBUG_COMBINATION)
2834 continue;
2835
Johan Hedberg7652ff62014-06-24 13:15:49 +03002836 hci_add_link_key(hdev, NULL, &key->addr.bdaddr, key->val,
2837 key->type, key->pin_len, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002838 }
2839
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002840 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002841
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002842 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002843
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002844 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002845}
2846
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002847static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002848 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002849{
2850 struct mgmt_ev_device_unpaired ev;
2851
2852 bacpy(&ev.addr.bdaddr, bdaddr);
2853 ev.addr.type = addr_type;
2854
2855 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002856 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002857}
2858
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002859static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002860 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002861{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002862 struct mgmt_cp_unpair_device *cp = data;
2863 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002864 struct hci_cp_disconnect dc;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002865 struct mgmt_pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002866 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002867 int err;
2868
Johan Hedberga8a1d192011-11-10 15:54:38 +02002869 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002870 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2871 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002872
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002873 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002874 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2875 MGMT_STATUS_INVALID_PARAMS,
2876 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002877
Johan Hedberg118da702013-01-20 14:27:20 +02002878 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002879 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2880 MGMT_STATUS_INVALID_PARAMS,
2881 &rp, sizeof(rp));
Johan Hedberg118da702013-01-20 14:27:20 +02002882
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002883 hci_dev_lock(hdev);
2884
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002885 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002886 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2887 MGMT_STATUS_NOT_POWERED, &rp,
2888 sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002889 goto unlock;
2890 }
2891
Johan Hedberge0b2b272014-02-18 17:14:31 +02002892 if (cp->addr.type == BDADDR_BREDR) {
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002893 /* If disconnection is requested, then look up the
2894 * connection. If the remote device is connected, it
2895 * will be later used to terminate the link.
2896 *
2897 * Setting it to NULL explicitly will cause no
2898 * termination of the link.
2899 */
2900 if (cp->disconnect)
2901 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2902 &cp->addr.bdaddr);
2903 else
2904 conn = NULL;
2905
Johan Hedberg124f6e32012-02-09 13:50:12 +02002906 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedberge0b2b272014-02-18 17:14:31 +02002907 } else {
2908 u8 addr_type;
2909
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002910 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
2911 &cp->addr.bdaddr);
2912 if (conn) {
2913 /* Defer clearing up the connection parameters
2914 * until closing to give a chance of keeping
2915 * them if a repairing happens.
2916 */
2917 set_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
2918
2919 /* If disconnection is not requested, then
2920 * clear the connection variable so that the
2921 * link is not terminated.
2922 */
2923 if (!cp->disconnect)
2924 conn = NULL;
2925 }
2926
Johan Hedberge0b2b272014-02-18 17:14:31 +02002927 if (cp->addr.type == BDADDR_LE_PUBLIC)
2928 addr_type = ADDR_LE_DEV_PUBLIC;
2929 else
2930 addr_type = ADDR_LE_DEV_RANDOM;
2931
Johan Hedberga7ec7332014-02-18 17:14:35 +02002932 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2933
Johan Hedberge0b2b272014-02-18 17:14:31 +02002934 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
2935 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002936
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002937 if (err < 0) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002938 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2939 MGMT_STATUS_NOT_PAIRED, &rp,
2940 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002941 goto unlock;
2942 }
2943
Alfonso Acosta89cbb062014-10-11 21:44:47 +00002944 /* If the connection variable is set, then termination of the
2945 * link is requested.
2946 */
Johan Hedberga8a1d192011-11-10 15:54:38 +02002947 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002948 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
2949 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002950 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002951 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002952 }
2953
Johan Hedberg124f6e32012-02-09 13:50:12 +02002954 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002955 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002956 if (!cmd) {
2957 err = -ENOMEM;
2958 goto unlock;
2959 }
2960
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02002961 cmd->cmd_complete = addr_cmd_complete;
2962
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002963 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002964 dc.reason = 0x13; /* Remote User Terminated Connection */
2965 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2966 if (err < 0)
2967 mgmt_pending_remove(cmd);
2968
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002969unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002970 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002971 return err;
2972}
2973
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002974static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002975 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002976{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002977 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002978 struct mgmt_rp_disconnect rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02002979 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002980 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002981 int err;
2982
2983 BT_DBG("");
2984
Johan Hedberg06a63b12013-01-20 14:27:21 +02002985 memset(&rp, 0, sizeof(rp));
2986 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2987 rp.addr.type = cp->addr.type;
2988
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002989 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002990 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2991 MGMT_STATUS_INVALID_PARAMS,
2992 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002993
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002994 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002995
2996 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02002997 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2998 MGMT_STATUS_NOT_POWERED, &rp,
2999 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003000 goto failed;
3001 }
3002
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003003 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003004 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
3005 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003006 goto failed;
3007 }
3008
Andre Guedes591f47f2012-04-24 21:02:49 -03003009 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003010 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
3011 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02003012 else
3013 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03003014
Vishal Agarwalf9607272012-06-13 05:32:43 +05303015 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003016 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
3017 MGMT_STATUS_NOT_CONNECTED, &rp,
3018 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003019 goto failed;
3020 }
3021
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003022 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03003023 if (!cmd) {
3024 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003025 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03003026 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02003027
Johan Hedbergf5818c22014-12-05 13:36:02 +02003028 cmd->cmd_complete = generic_cmd_complete;
3029
Johan Hedberge3f2f922014-08-18 20:33:33 +03003030 err = hci_disconnect(conn, HCI_ERROR_REMOTE_USER_TERM);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003031 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03003032 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003033
3034failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003035 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003036 return err;
3037}
3038
Andre Guedes57c14772012-04-24 21:02:50 -03003039static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02003040{
3041 switch (link_type) {
3042 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02003043 switch (addr_type) {
3044 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03003045 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03003046
Johan Hedberg48264f02011-11-09 13:58:58 +02003047 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03003048 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03003049 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02003050 }
Andre Guedes0ed09142012-04-03 08:46:54 -03003051
Johan Hedberg4c659c32011-11-07 23:13:39 +02003052 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03003053 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03003054 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02003055 }
3056}
3057
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003058static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
3059 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02003060{
Johan Hedberg2784eb42011-01-21 13:56:35 +02003061 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02003062 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02003063 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003064 int err;
3065 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02003066
3067 BT_DBG("");
3068
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003069 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003070
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003071 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003072 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
3073 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003074 goto unlock;
3075 }
3076
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003077 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02003078 list_for_each_entry(c, &hdev->conn_hash.list, list) {
3079 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003080 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02003081 }
3082
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003083 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03003084 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02003085 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02003086 err = -ENOMEM;
3087 goto unlock;
3088 }
3089
Johan Hedberg2784eb42011-01-21 13:56:35 +02003090 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02003091 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02003092 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
3093 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02003094 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03003095 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03003096 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02003097 continue;
3098 i++;
3099 }
3100
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003101 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02003102
Johan Hedberg4c659c32011-11-07 23:13:39 +02003103 /* Recalculate length in case of filtered SCO connections, etc */
3104 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02003105
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003106 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
3107 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003108
Johan Hedberga38528f2011-01-22 06:46:43 +02003109 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003110
3111unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003112 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02003113 return err;
3114}
3115
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003116static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003117 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003118{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003119 struct mgmt_pending_cmd *cmd;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003120 int err;
3121
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003122 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003123 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003124 if (!cmd)
3125 return -ENOMEM;
3126
Johan Hedbergd8457692012-02-17 14:24:57 +02003127 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003128 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003129 if (err < 0)
3130 mgmt_pending_remove(cmd);
3131
3132 return err;
3133}
3134
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003135static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003136 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003137{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003138 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003139 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003140 struct hci_cp_pin_code_reply reply;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003141 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003142 int err;
3143
3144 BT_DBG("");
3145
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003146 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003147
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003148 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003149 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3150 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003151 goto failed;
3152 }
3153
Johan Hedbergd8457692012-02-17 14:24:57 +02003154 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003155 if (!conn) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003156 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3157 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003158 goto failed;
3159 }
3160
3161 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02003162 struct mgmt_cp_pin_code_neg_reply ncp;
3163
3164 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003165
3166 BT_ERR("PIN code is not 16 bytes long");
3167
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003168 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003169 if (err >= 0)
Johan Hedberga69e8372015-03-06 21:08:53 +02003170 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3171 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02003172
3173 goto failed;
3174 }
3175
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03003176 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03003177 if (!cmd) {
3178 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003179 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03003180 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02003181
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003182 cmd->cmd_complete = addr_cmd_complete;
3183
Johan Hedbergd8457692012-02-17 14:24:57 +02003184 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003185 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02003186 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003187
3188 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
3189 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03003190 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003191
3192failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003193 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003194 return err;
3195}
3196
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003197static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
3198 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003199{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003200 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003201
3202 BT_DBG("");
3203
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003204 if (cp->io_capability > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003205 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY,
3206 MGMT_STATUS_INVALID_PARAMS, NULL, 0);
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003207
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003208 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003209
3210 hdev->io_capability = cp->io_capability;
3211
3212 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003213 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003214
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003215 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003216
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003217 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0,
3218 NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02003219}
3220
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003221static struct mgmt_pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003222{
3223 struct hci_dev *hdev = conn->hdev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003224 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003225
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003226 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03003227 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
3228 continue;
3229
Johan Hedberge9a416b2011-02-19 12:05:56 -03003230 if (cmd->user_data != conn)
3231 continue;
3232
3233 return cmd;
3234 }
3235
3236 return NULL;
3237}
3238
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003239static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003240{
3241 struct mgmt_rp_pair_device rp;
3242 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9df74652014-12-19 22:26:03 +02003243 int err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003244
Johan Hedberg61b1a7f2014-03-20 12:54:16 +02003245 bacpy(&rp.addr.bdaddr, &conn->dst);
3246 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003247
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003248 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
3249 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003250
3251 /* So we don't get further callbacks for this connection */
3252 conn->connect_cfm_cb = NULL;
3253 conn->security_cfm_cb = NULL;
3254 conn->disconn_cfm_cb = NULL;
3255
David Herrmann76a68ba2013-04-06 20:28:37 +02003256 hci_conn_drop(conn);
Alfonso Acosta89cbb062014-10-11 21:44:47 +00003257
3258 /* The device is paired so there is no need to remove
3259 * its connection parameters anymore.
3260 */
3261 clear_bit(HCI_CONN_PARAM_REMOVAL_PEND, &conn->flags);
Johan Hedberg15013ae2014-12-11 21:45:44 +02003262
3263 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02003264
3265 return err;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003266}
3267
Johan Hedbergf4a407be2014-02-18 21:41:34 +02003268void mgmt_smp_complete(struct hci_conn *conn, bool complete)
3269{
3270 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003271 struct mgmt_pending_cmd *cmd;
Johan Hedbergf4a407be2014-02-18 21:41:34 +02003272
3273 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003274 if (cmd) {
Johan Hedberg04ab2742014-12-05 13:36:04 +02003275 cmd->cmd_complete(cmd, status);
Johan Hedberga511b352014-12-11 21:45:45 +02003276 mgmt_pending_remove(cmd);
3277 }
Johan Hedbergf4a407be2014-02-18 21:41:34 +02003278}
3279
Johan Hedberge9a416b2011-02-19 12:05:56 -03003280static void pairing_complete_cb(struct hci_conn *conn, u8 status)
3281{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003282 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003283
3284 BT_DBG("status %u", status);
3285
Johan Hedberg56e5cb82011-11-08 20:40:16 +02003286 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003287 if (!cmd) {
Johan Hedberg56e5cb82011-11-08 20:40:16 +02003288 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02003289 return;
3290 }
3291
3292 cmd->cmd_complete(cmd, mgmt_status(status));
3293 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003294}
3295
Johan Hedbergf4a407be2014-02-18 21:41:34 +02003296static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303297{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003298 struct mgmt_pending_cmd *cmd;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303299
3300 BT_DBG("status %u", status);
3301
3302 if (!status)
3303 return;
3304
3305 cmd = find_pairing(conn);
Johan Hedberga511b352014-12-11 21:45:45 +02003306 if (!cmd) {
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303307 BT_DBG("Unable to find a pending command");
Johan Hedberga511b352014-12-11 21:45:45 +02003308 return;
3309 }
3310
3311 cmd->cmd_complete(cmd, mgmt_status(status));
3312 mgmt_pending_remove(cmd);
Vishal Agarwal4c47d732012-06-07 20:27:35 +05303313}
3314
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003315static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003316 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03003317{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003318 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02003319 struct mgmt_rp_pair_device rp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003320 struct mgmt_pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003321 u8 sec_level, auth_type;
3322 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003323 int err;
3324
3325 BT_DBG("");
3326
Szymon Jancf950a30e2013-01-18 12:48:07 +01003327 memset(&rp, 0, sizeof(rp));
3328 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3329 rp.addr.type = cp->addr.type;
3330
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003331 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003332 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3333 MGMT_STATUS_INVALID_PARAMS,
3334 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003335
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003336 if (cp->io_cap > SMP_IO_KEYBOARD_DISPLAY)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003337 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3338 MGMT_STATUS_INVALID_PARAMS,
3339 &rp, sizeof(rp));
Johan Hedberg4ec86d42014-06-17 15:14:48 +03003340
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003341 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003342
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003343 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003344 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3345 MGMT_STATUS_NOT_POWERED, &rp,
3346 sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003347 goto unlock;
3348 }
3349
Johan Hedberg55e76b32015-03-10 22:34:40 +02003350 if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
3351 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3352 MGMT_STATUS_ALREADY_PAIRED, &rp,
3353 sizeof(rp));
3354 goto unlock;
3355 }
3356
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03003357 sec_level = BT_SECURITY_MEDIUM;
Mikel Astiz6fd6b912014-04-08 14:21:32 +02003358 auth_type = HCI_AT_DEDICATED_BONDING;
Johan Hedberge9a416b2011-02-19 12:05:56 -03003359
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003360 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03003361 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
3362 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003363 } else {
3364 u8 addr_type;
3365
3366 /* Convert from L2CAP channel address type to HCI address type
3367 */
3368 if (cp->addr.type == BDADDR_LE_PUBLIC)
3369 addr_type = ADDR_LE_DEV_PUBLIC;
3370 else
3371 addr_type = ADDR_LE_DEV_RANDOM;
3372
Marcel Holtmann7c264b12014-06-30 12:34:40 +02003373 /* When pairing a new device, it is expected to remember
3374 * this device for future connections. Adding the connection
3375 * parameter information ahead of time allows tracking
3376 * of the slave preferred values and will speed up any
3377 * further connection establishment.
3378 *
3379 * If connection parameters already exist, then they
3380 * will be kept and this function does nothing.
3381 */
3382 hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type);
3383
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003384 conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type,
Johan Hedberge804d252014-07-16 11:42:28 +03003385 sec_level, HCI_LE_CONN_TIMEOUT,
3386 HCI_ROLE_MASTER);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03003387 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003388
Ville Tervo30e76272011-02-22 16:10:53 -03003389 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003390 int status;
3391
3392 if (PTR_ERR(conn) == -EBUSY)
3393 status = MGMT_STATUS_BUSY;
Lukasz Rymanowskifaa81032015-02-11 12:31:42 +01003394 else if (PTR_ERR(conn) == -EOPNOTSUPP)
3395 status = MGMT_STATUS_NOT_SUPPORTED;
3396 else if (PTR_ERR(conn) == -ECONNREFUSED)
3397 status = MGMT_STATUS_REJECTED;
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02003398 else
3399 status = MGMT_STATUS_CONNECT_FAILED;
3400
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003401 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3402 status, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003403 goto unlock;
3404 }
3405
3406 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02003407 hci_conn_drop(conn);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003408 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
3409 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03003410 goto unlock;
3411 }
3412
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003413 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003414 if (!cmd) {
3415 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02003416 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003417 goto unlock;
3418 }
3419
Johan Hedberg04ab2742014-12-05 13:36:04 +02003420 cmd->cmd_complete = pairing_complete;
3421
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003422 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407be2014-02-18 21:41:34 +02003423 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003424 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407be2014-02-18 21:41:34 +02003425 conn->security_cfm_cb = pairing_complete_cb;
3426 conn->disconn_cfm_cb = pairing_complete_cb;
3427 } else {
3428 conn->connect_cfm_cb = le_pairing_complete_cb;
3429 conn->security_cfm_cb = le_pairing_complete_cb;
3430 conn->disconn_cfm_cb = le_pairing_complete_cb;
3431 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03003432
Johan Hedberge9a416b2011-02-19 12:05:56 -03003433 conn->io_capability = cp->io_cap;
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03003434 cmd->user_data = hci_conn_get(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003435
Johan Hedberg6f78fd42014-07-30 08:35:48 +03003436 if ((conn->state == BT_CONNECTED || conn->state == BT_CONFIG) &&
Johan Hedberga511b352014-12-11 21:45:45 +02003437 hci_conn_security(conn, sec_level, auth_type, true)) {
3438 cmd->cmd_complete(cmd, 0);
3439 mgmt_pending_remove(cmd);
3440 }
Johan Hedberge9a416b2011-02-19 12:05:56 -03003441
3442 err = 0;
3443
3444unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003445 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03003446 return err;
3447}
3448
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003449static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
3450 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02003451{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003452 struct mgmt_addr_info *addr = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003453 struct mgmt_pending_cmd *cmd;
Johan Hedberg28424702012-02-02 04:02:29 +02003454 struct hci_conn *conn;
3455 int err;
3456
3457 BT_DBG("");
3458
Johan Hedberg28424702012-02-02 04:02:29 +02003459 hci_dev_lock(hdev);
3460
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003461 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003462 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3463 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02003464 goto unlock;
3465 }
3466
Johan Hedberg28424702012-02-02 04:02:29 +02003467 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
3468 if (!cmd) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003469 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3470 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003471 goto unlock;
3472 }
3473
3474 conn = cmd->user_data;
3475
3476 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003477 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
3478 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02003479 goto unlock;
3480 }
3481
Johan Hedberga511b352014-12-11 21:45:45 +02003482 cmd->cmd_complete(cmd, MGMT_STATUS_CANCELLED);
3483 mgmt_pending_remove(cmd);
Johan Hedberg28424702012-02-02 04:02:29 +02003484
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003485 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
3486 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02003487unlock:
3488 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02003489 return err;
3490}
3491
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003492static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05003493 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003494 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03003495{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003496 struct mgmt_pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08003497 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03003498 int err;
3499
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003500 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02003501
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003502 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003503 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3504 MGMT_STATUS_NOT_POWERED, addr,
3505 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08003506 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003507 }
3508
Johan Hedberg1707c602013-03-15 17:07:15 -05003509 if (addr->type == BDADDR_BREDR)
3510 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02003511 else
Johan Hedberg1707c602013-03-15 17:07:15 -05003512 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08003513
Johan Hedberg272d90d2012-02-09 15:26:12 +02003514 if (!conn) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003515 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3516 MGMT_STATUS_NOT_CONNECTED, addr,
3517 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02003518 goto done;
3519 }
3520
Johan Hedberg1707c602013-03-15 17:07:15 -05003521 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix5fe57d92011-12-21 16:12:13 -08003522 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix5fe57d92011-12-21 16:12:13 -08003523 if (!err)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003524 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3525 MGMT_STATUS_SUCCESS, addr,
3526 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003527 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003528 err = mgmt_cmd_complete(sk, hdev->id, mgmt_op,
3529 MGMT_STATUS_FAILED, addr,
3530 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08003531
Brian Gix47c15e22011-11-16 13:53:14 -08003532 goto done;
3533 }
3534
Johan Hedberg1707c602013-03-15 17:07:15 -05003535 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03003536 if (!cmd) {
3537 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08003538 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03003539 }
3540
Johan Hedberg7776d1d2014-12-05 13:36:03 +02003541 cmd->cmd_complete = addr_cmd_complete;
3542
Brian Gix0df4c182011-11-16 13:53:13 -08003543 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08003544 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
3545 struct hci_cp_user_passkey_reply cp;
3546
Johan Hedberg1707c602013-03-15 17:07:15 -05003547 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003548 cp.passkey = passkey;
3549 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
3550 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05003551 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
3552 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08003553
Johan Hedberga664b5b2011-02-19 12:06:02 -03003554 if (err < 0)
3555 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003556
Brian Gix0df4c182011-11-16 13:53:13 -08003557done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003558 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003559 return err;
3560}
3561
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303562static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3563 void *data, u16 len)
3564{
3565 struct mgmt_cp_pin_code_neg_reply *cp = data;
3566
3567 BT_DBG("");
3568
Johan Hedberg1707c602013-03-15 17:07:15 -05003569 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303570 MGMT_OP_PIN_CODE_NEG_REPLY,
3571 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3572}
3573
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003574static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3575 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003576{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003577 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003578
3579 BT_DBG("");
3580
3581 if (len != sizeof(*cp))
Johan Hedberga69e8372015-03-06 21:08:53 +02003582 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
3583 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003584
Johan Hedberg1707c602013-03-15 17:07:15 -05003585 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003586 MGMT_OP_USER_CONFIRM_REPLY,
3587 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003588}
3589
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003590static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003591 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003592{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003593 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003594
3595 BT_DBG("");
3596
Johan Hedberg1707c602013-03-15 17:07:15 -05003597 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003598 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3599 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003600}
3601
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003602static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3603 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003604{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003605 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003606
3607 BT_DBG("");
3608
Johan Hedberg1707c602013-03-15 17:07:15 -05003609 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003610 MGMT_OP_USER_PASSKEY_REPLY,
3611 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003612}
3613
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003614static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003615 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003616{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003617 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003618
3619 BT_DBG("");
3620
Johan Hedberg1707c602013-03-15 17:07:15 -05003621 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003622 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3623 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003624}
3625
Johan Hedberg13928972013-03-15 17:07:00 -05003626static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003627{
Johan Hedberg13928972013-03-15 17:07:00 -05003628 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003629 struct hci_cp_write_local_name cp;
3630
Johan Hedberg13928972013-03-15 17:07:00 -05003631 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003632
Johan Hedberg890ea892013-03-15 17:06:52 -05003633 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003634}
3635
Marcel Holtmann1904a852015-01-11 13:50:44 -08003636static void set_name_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg13928972013-03-15 17:07:00 -05003637{
3638 struct mgmt_cp_set_local_name *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003639 struct mgmt_pending_cmd *cmd;
Johan Hedberg13928972013-03-15 17:07:00 -05003640
3641 BT_DBG("status 0x%02x", status);
3642
3643 hci_dev_lock(hdev);
3644
3645 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
3646 if (!cmd)
3647 goto unlock;
3648
3649 cp = cmd->param;
3650
3651 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02003652 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3653 mgmt_status(status));
Johan Hedberg13928972013-03-15 17:07:00 -05003654 else
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003655 mgmt_cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3656 cp, sizeof(*cp));
Johan Hedberg13928972013-03-15 17:07:00 -05003657
3658 mgmt_pending_remove(cmd);
3659
3660unlock:
3661 hci_dev_unlock(hdev);
3662}
3663
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003664static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003665 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003666{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003667 struct mgmt_cp_set_local_name *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003668 struct mgmt_pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003669 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003670 int err;
3671
3672 BT_DBG("");
3673
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003674 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003675
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003676 /* If the old values are the same as the new ones just return a
3677 * direct command complete event.
3678 */
3679 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3680 !memcmp(hdev->short_name, cp->short_name,
3681 sizeof(hdev->short_name))) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003682 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3683 data, len);
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003684 goto failed;
3685 }
3686
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003687 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003688
Johan Hedbergb5235a62012-02-21 14:32:24 +02003689 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003690 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003691
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003692 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3693 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003694 if (err < 0)
3695 goto failed;
3696
Marcel Holtmannf6b77122015-03-14 19:28:05 -07003697 err = mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev,
3698 data, len, sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003699
Johan Hedbergb5235a62012-02-21 14:32:24 +02003700 goto failed;
3701 }
3702
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003703 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003704 if (!cmd) {
3705 err = -ENOMEM;
3706 goto failed;
3707 }
3708
Johan Hedberg13928972013-03-15 17:07:00 -05003709 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3710
Johan Hedberg890ea892013-03-15 17:06:52 -05003711 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003712
3713 if (lmp_bredr_capable(hdev)) {
3714 update_name(&req);
3715 update_eir(&req);
3716 }
3717
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003718 /* The name is stored in the scan response data and so
3719 * no need to udpate the advertising data here.
3720 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003721 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003722 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003723
Johan Hedberg13928972013-03-15 17:07:00 -05003724 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003725 if (err < 0)
3726 mgmt_pending_remove(cmd);
3727
3728failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003729 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003730 return err;
3731}
3732
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003733static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003734 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003735{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02003736 struct mgmt_pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01003737 int err;
3738
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003739 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003740
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003741 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003742
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003743 if (!hdev_is_powered(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003744 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3745 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003746 goto unlock;
3747 }
3748
Andre Guedes9a1a1992012-07-24 15:03:48 -03003749 if (!lmp_ssp_capable(hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003750 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3751 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003752 goto unlock;
3753 }
3754
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003755 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02003756 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3757 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003758 goto unlock;
3759 }
3760
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003761 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003762 if (!cmd) {
3763 err = -ENOMEM;
3764 goto unlock;
3765 }
3766
Johan Hedberg710f11c2014-05-26 11:21:22 +03003767 if (bredr_sc_enabled(hdev))
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003768 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
3769 0, NULL);
3770 else
3771 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3772
Szymon Jancc35938b2011-03-22 13:12:21 +01003773 if (err < 0)
3774 mgmt_pending_remove(cmd);
3775
3776unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003777 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003778 return err;
3779}
3780
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003781static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003782 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003783{
Johan Hedberg5d57e792015-01-23 10:10:38 +02003784 struct mgmt_addr_info *addr = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01003785 int err;
3786
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003787 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003788
Johan Hedberg5d57e792015-01-23 10:10:38 +02003789 if (!bdaddr_type_is_valid(addr->type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003790 return mgmt_cmd_complete(sk, hdev->id,
3791 MGMT_OP_ADD_REMOTE_OOB_DATA,
3792 MGMT_STATUS_INVALID_PARAMS,
3793 addr, sizeof(*addr));
Johan Hedberg5d57e792015-01-23 10:10:38 +02003794
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003795 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003796
Marcel Holtmannec109112014-01-10 02:07:30 -08003797 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3798 struct mgmt_cp_add_remote_oob_data *cp = data;
3799 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003800
Johan Hedbergc19a4952014-11-17 20:52:19 +02003801 if (cp->addr.type != BDADDR_BREDR) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003802 err = mgmt_cmd_complete(sk, hdev->id,
3803 MGMT_OP_ADD_REMOTE_OOB_DATA,
3804 MGMT_STATUS_INVALID_PARAMS,
3805 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003806 goto unlock;
3807 }
3808
Marcel Holtmannec109112014-01-10 02:07:30 -08003809 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg6928a922014-10-26 20:46:09 +01003810 cp->addr.type, cp->hash,
3811 cp->rand, NULL, NULL);
Marcel Holtmannec109112014-01-10 02:07:30 -08003812 if (err < 0)
3813 status = MGMT_STATUS_FAILED;
3814 else
3815 status = MGMT_STATUS_SUCCESS;
3816
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003817 err = mgmt_cmd_complete(sk, hdev->id,
3818 MGMT_OP_ADD_REMOTE_OOB_DATA, status,
3819 &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003820 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3821 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003822 u8 *rand192, *hash192, *rand256, *hash256;
Marcel Holtmannec109112014-01-10 02:07:30 -08003823 u8 status;
3824
Johan Hedberg86df9202014-10-26 20:52:27 +01003825 if (bdaddr_type_is_le(cp->addr.type)) {
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003826 /* Enforce zero-valued 192-bit parameters as
3827 * long as legacy SMP OOB isn't implemented.
3828 */
3829 if (memcmp(cp->rand192, ZERO_KEY, 16) ||
3830 memcmp(cp->hash192, ZERO_KEY, 16)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003831 err = mgmt_cmd_complete(sk, hdev->id,
3832 MGMT_OP_ADD_REMOTE_OOB_DATA,
3833 MGMT_STATUS_INVALID_PARAMS,
3834 addr, sizeof(*addr));
Johan Hedbergd25b78e2015-01-27 12:55:52 +02003835 goto unlock;
3836 }
3837
Johan Hedberg86df9202014-10-26 20:52:27 +01003838 rand192 = NULL;
3839 hash192 = NULL;
3840 } else {
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003841 /* In case one of the P-192 values is set to zero,
3842 * then just disable OOB data for P-192.
3843 */
3844 if (!memcmp(cp->rand192, ZERO_KEY, 16) ||
3845 !memcmp(cp->hash192, ZERO_KEY, 16)) {
3846 rand192 = NULL;
3847 hash192 = NULL;
3848 } else {
3849 rand192 = cp->rand192;
3850 hash192 = cp->hash192;
3851 }
3852 }
3853
3854 /* In case one of the P-256 values is set to zero, then just
3855 * disable OOB data for P-256.
3856 */
3857 if (!memcmp(cp->rand256, ZERO_KEY, 16) ||
3858 !memcmp(cp->hash256, ZERO_KEY, 16)) {
3859 rand256 = NULL;
3860 hash256 = NULL;
3861 } else {
3862 rand256 = cp->rand256;
3863 hash256 = cp->hash256;
Johan Hedberg86df9202014-10-26 20:52:27 +01003864 }
3865
Johan Hedberg81328d5c2014-10-26 20:33:47 +01003866 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
Johan Hedberg86df9202014-10-26 20:52:27 +01003867 cp->addr.type, hash192, rand192,
Marcel Holtmann41bcfd52015-01-31 00:37:02 -08003868 hash256, rand256);
Marcel Holtmannec109112014-01-10 02:07:30 -08003869 if (err < 0)
3870 status = MGMT_STATUS_FAILED;
3871 else
3872 status = MGMT_STATUS_SUCCESS;
3873
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003874 err = mgmt_cmd_complete(sk, hdev->id,
3875 MGMT_OP_ADD_REMOTE_OOB_DATA,
3876 status, &cp->addr, sizeof(cp->addr));
Marcel Holtmannec109112014-01-10 02:07:30 -08003877 } else {
3878 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
Johan Hedberga69e8372015-03-06 21:08:53 +02003879 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3880 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannec109112014-01-10 02:07:30 -08003881 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003882
Johan Hedbergc19a4952014-11-17 20:52:19 +02003883unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003884 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003885 return err;
3886}
3887
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003888static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003889 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003890{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003891 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003892 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003893 int err;
3894
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003895 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003896
Johan Hedbergc19a4952014-11-17 20:52:19 +02003897 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003898 return mgmt_cmd_complete(sk, hdev->id,
3899 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3900 MGMT_STATUS_INVALID_PARAMS,
3901 &cp->addr, sizeof(cp->addr));
Johan Hedbergc19a4952014-11-17 20:52:19 +02003902
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003903 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003904
Johan Hedbergeedbd582014-11-15 09:34:23 +02003905 if (!bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
3906 hci_remote_oob_data_clear(hdev);
3907 status = MGMT_STATUS_SUCCESS;
3908 goto done;
3909 }
3910
Johan Hedberg6928a922014-10-26 20:46:09 +01003911 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr, cp->addr.type);
Szymon Janc2763eda2011-03-22 13:12:22 +01003912 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003913 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003914 else
Szymon Janca6785be2012-12-13 15:11:21 +01003915 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003916
Johan Hedbergeedbd582014-11-15 09:34:23 +02003917done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02003918 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
3919 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003920
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003921 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003922 return err;
3923}
3924
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003925static bool trigger_bredr_inquiry(struct hci_request *req, u8 *status)
3926{
3927 struct hci_dev *hdev = req->hdev;
3928 struct hci_cp_inquiry cp;
3929 /* General inquiry access code (GIAC) */
3930 u8 lap[3] = { 0x33, 0x8b, 0x9e };
3931
3932 *status = mgmt_bredr_support(hdev);
3933 if (*status)
3934 return false;
3935
3936 if (hci_dev_test_flag(hdev, HCI_INQUIRY)) {
3937 *status = MGMT_STATUS_BUSY;
3938 return false;
3939 }
3940
3941 hci_inquiry_cache_flush(hdev);
3942
3943 memset(&cp, 0, sizeof(cp));
3944 memcpy(&cp.lap, lap, sizeof(cp.lap));
3945 cp.length = DISCOV_BREDR_INQUIRY_LEN;
3946
3947 hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp);
3948
3949 return true;
3950}
3951
3952static bool trigger_le_scan(struct hci_request *req, u16 interval, u8 *status)
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003953{
Marcel Holtmann80190442014-12-04 11:36:36 +01003954 struct hci_dev *hdev = req->hdev;
3955 struct hci_cp_le_set_scan_param param_cp;
3956 struct hci_cp_le_set_scan_enable enable_cp;
Marcel Holtmann80190442014-12-04 11:36:36 +01003957 u8 own_addr_type;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003958 int err;
3959
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003960 *status = mgmt_le_support(hdev);
3961 if (*status)
3962 return false;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003963
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003964 if (hci_dev_test_flag(hdev, HCI_LE_ADV)) {
3965 /* Don't let discovery abort an outgoing connection attempt
3966 * that's using directed advertising.
3967 */
3968 if (hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT)) {
3969 *status = MGMT_STATUS_REJECTED;
Marcel Holtmann80190442014-12-04 11:36:36 +01003970 return false;
3971 }
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003972
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003973 disable_advertising(req);
3974 }
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003975
Jakub Pawlowski812abb12015-03-17 09:04:13 -07003976 /* If controller is scanning, it means the background scanning is
3977 * running. Thus, we should temporarily stop it in order to set the
3978 * discovery scanning parameters.
3979 */
3980 if (hci_dev_test_flag(hdev, HCI_LE_SCAN))
3981 hci_req_add_le_scan_disable(req);
3982
3983 /* All active scans will be done with either a resolvable private
3984 * address (when privacy feature has been enabled) or non-resolvable
3985 * private address.
3986 */
3987 err = hci_update_random_address(req, true, &own_addr_type);
3988 if (err < 0) {
3989 *status = MGMT_STATUS_FAILED;
3990 return false;
3991 }
3992
3993 memset(&param_cp, 0, sizeof(param_cp));
3994 param_cp.type = LE_SCAN_ACTIVE;
3995 param_cp.interval = cpu_to_le16(interval);
3996 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
3997 param_cp.own_address_type = own_addr_type;
3998
3999 hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
4000 &param_cp);
4001
4002 memset(&enable_cp, 0, sizeof(enable_cp));
4003 enable_cp.enable = LE_SCAN_ENABLE;
4004 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
4005
4006 hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
4007 &enable_cp);
4008
4009 return true;
4010}
4011
4012static bool trigger_discovery(struct hci_request *req, u8 *status)
4013{
4014 struct hci_dev *hdev = req->hdev;
4015
4016 switch (hdev->discovery.type) {
4017 case DISCOV_TYPE_BREDR:
4018 if (!trigger_bredr_inquiry(req, status))
4019 return false;
Marcel Holtmann80190442014-12-04 11:36:36 +01004020 break;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03004021
Marcel Holtmann80190442014-12-04 11:36:36 +01004022 case DISCOV_TYPE_INTERLEAVED:
Jakub Pawlowski07d23342015-03-17 09:04:14 -07004023 if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY,
4024 &hdev->quirks)) {
4025 /* During simultaneous discovery, we double LE scan
4026 * interval. We must leave some time for the controller
4027 * to do BR/EDR inquiry.
4028 */
4029 if (!trigger_le_scan(req, DISCOV_LE_SCAN_INT * 2,
4030 status))
4031 return false;
4032
4033 if (!trigger_bredr_inquiry(req, status))
4034 return false;
4035
4036 return true;
4037 }
4038
Jakub Pawlowski812abb12015-03-17 09:04:13 -07004039 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmann80190442014-12-04 11:36:36 +01004040 *status = MGMT_STATUS_NOT_SUPPORTED;
4041 return false;
4042 }
Jakub Pawlowski812abb12015-03-17 09:04:13 -07004043 /* fall through */
Marcel Holtmann80190442014-12-04 11:36:36 +01004044
Jakub Pawlowski812abb12015-03-17 09:04:13 -07004045 case DISCOV_TYPE_LE:
4046 if (!trigger_le_scan(req, DISCOV_LE_SCAN_INT, status))
Marcel Holtmann80190442014-12-04 11:36:36 +01004047 return false;
Marcel Holtmann80190442014-12-04 11:36:36 +01004048 break;
4049
4050 default:
4051 *status = MGMT_STATUS_INVALID_PARAMS;
4052 return false;
4053 }
4054
4055 return true;
Andre Guedes41dc2bd2013-04-30 15:29:30 -03004056}
4057
Marcel Holtmann1904a852015-01-11 13:50:44 -08004058static void start_discovery_complete(struct hci_dev *hdev, u8 status,
4059 u16 opcode)
Andre Guedes7c307722013-04-30 15:29:28 -03004060{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004061 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004062 unsigned long timeout;
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004063
Andre Guedes7c307722013-04-30 15:29:28 -03004064 BT_DBG("status %d", status);
4065
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004066 hci_dev_lock(hdev);
4067
4068 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004069 if (!cmd)
4070 cmd = mgmt_pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev);
4071
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004072 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004073 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004074 mgmt_pending_remove(cmd);
Andre Guedes7c307722013-04-30 15:29:28 -03004075 }
4076
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004077 if (status) {
4078 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
4079 goto unlock;
4080 }
4081
Andre Guedes7c307722013-04-30 15:29:28 -03004082 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
Andre Guedes7c307722013-04-30 15:29:28 -03004083
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004084 /* If the scan involves LE scan, pick proper timeout to schedule
4085 * hdev->le_scan_disable that will stop it.
4086 */
Andre Guedes7c307722013-04-30 15:29:28 -03004087 switch (hdev->discovery.type) {
4088 case DISCOV_TYPE_LE:
Lukasz Rymanowski3d5a76f2014-03-27 20:55:21 +01004089 timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03004090 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004091 case DISCOV_TYPE_INTERLEAVED:
Jakub Pawlowski07d23342015-03-17 09:04:14 -07004092 /* When running simultaneous discovery, the LE scanning time
4093 * should occupy the whole discovery time sine BR/EDR inquiry
4094 * and LE scanning are scheduled by the controller.
4095 *
4096 * For interleaving discovery in comparison, BR/EDR inquiry
4097 * and LE scanning are done sequentially with separate
4098 * timeouts.
4099 */
4100 if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks))
4101 timeout = msecs_to_jiffies(DISCOV_LE_TIMEOUT);
4102 else
4103 timeout = msecs_to_jiffies(hdev->discov_interleaved_timeout);
Andre Guedes7c307722013-04-30 15:29:28 -03004104 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004105 case DISCOV_TYPE_BREDR:
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004106 timeout = 0;
Andre Guedes7c307722013-04-30 15:29:28 -03004107 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004108 default:
4109 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004110 timeout = 0;
4111 break;
Andre Guedes7c307722013-04-30 15:29:28 -03004112 }
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004113
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004114 if (timeout) {
4115 /* When service discovery is used and the controller has
4116 * a strict duplicate filter, it is important to remember
4117 * the start and duration of the scan. This is required
4118 * for restarting scanning during the discovery phase.
4119 */
4120 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER,
4121 &hdev->quirks) &&
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004122 hdev->discovery.result_filtering) {
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004123 hdev->discovery.scan_start = jiffies;
4124 hdev->discovery.scan_duration = timeout;
4125 }
4126
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004127 queue_delayed_work(hdev->workqueue,
4128 &hdev->le_scan_disable, timeout);
Jakub Pawlowski2d28cfe2015-02-01 23:07:54 -08004129 }
Lukasz Rymanowskiae55f592014-03-27 20:55:19 +01004130
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004131unlock:
4132 hci_dev_unlock(hdev);
Andre Guedes7c307722013-04-30 15:29:28 -03004133}
4134
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004135static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004136 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004137{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004138 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004139 struct mgmt_pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03004140 struct hci_request req;
Marcel Holtmann80190442014-12-04 11:36:36 +01004141 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04004142 int err;
4143
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004144 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004145
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004146 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004147
Johan Hedberg4b34ee782012-02-21 14:13:02 +02004148 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004149 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4150 MGMT_STATUS_NOT_POWERED,
4151 &cp->type, sizeof(cp->type));
Johan Hedbergbd2d1332011-11-07 23:13:37 +02004152 goto failed;
4153 }
4154
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004155 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004156 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004157 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4158 MGMT_STATUS_BUSY, &cp->type,
4159 sizeof(cp->type));
Andre Guedes642be6c2012-03-21 00:03:37 -03004160 goto failed;
4161 }
4162
Johan Hedberg2922a942014-12-05 13:36:06 +02004163 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004164 if (!cmd) {
4165 err = -ENOMEM;
4166 goto failed;
4167 }
4168
Johan Hedberg2922a942014-12-05 13:36:06 +02004169 cmd->cmd_complete = generic_cmd_complete;
4170
Marcel Holtmann22078802014-12-05 11:45:22 +01004171 /* Clear the discovery filter first to free any previously
4172 * allocated memory for the UUID list.
4173 */
4174 hci_discovery_filter_clear(hdev);
4175
Andre Guedes4aab14e2012-02-17 20:39:36 -03004176 hdev->discovery.type = cp->type;
Marcel Holtmannda25cf62014-12-05 13:03:35 +01004177 hdev->discovery.report_invalid_rssi = false;
Andre Guedes4aab14e2012-02-17 20:39:36 -03004178
Andre Guedes7c307722013-04-30 15:29:28 -03004179 hci_req_init(&req, hdev);
4180
Marcel Holtmann80190442014-12-04 11:36:36 +01004181 if (!trigger_discovery(&req, &status)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004182 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
4183 status, &cp->type, sizeof(cp->type));
Johan Hedberg04106752013-01-10 14:54:09 +02004184 mgmt_pending_remove(cmd);
4185 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03004186 }
Andre Guedes3fd24152012-02-03 17:48:01 -03004187
Andre Guedes7c307722013-04-30 15:29:28 -03004188 err = hci_req_run(&req, start_discovery_complete);
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004189 if (err < 0) {
Johan Hedberg14a53662011-04-27 10:29:56 -04004190 mgmt_pending_remove(cmd);
Marcel Holtmannf5a969f2014-12-04 11:36:34 +01004191 goto failed;
4192 }
4193
4194 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04004195
4196failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004197 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004198 return err;
4199}
4200
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004201static int service_discovery_cmd_complete(struct mgmt_pending_cmd *cmd,
4202 u8 status)
Andre Guedes1183fdc2013-04-30 15:29:35 -03004203{
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004204 return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
4205 cmd->param, 1);
Johan Hedberg2922a942014-12-05 13:36:06 +02004206}
4207
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004208static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
4209 void *data, u16 len)
4210{
4211 struct mgmt_cp_start_service_discovery *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004212 struct mgmt_pending_cmd *cmd;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004213 struct hci_request req;
4214 const u16 max_uuid_count = ((U16_MAX - sizeof(*cp)) / 16);
4215 u16 uuid_count, expected_len;
4216 u8 status;
Andre Guedes1183fdc2013-04-30 15:29:35 -03004217 int err;
4218
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004219 BT_DBG("%s", hdev->name);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004220
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004221 hci_dev_lock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004222
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004223 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004224 err = mgmt_cmd_complete(sk, hdev->id,
4225 MGMT_OP_START_SERVICE_DISCOVERY,
4226 MGMT_STATUS_NOT_POWERED,
4227 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004228 goto failed;
4229 }
4230
4231 if (hdev->discovery.state != DISCOVERY_STOPPED ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004232 hci_dev_test_flag(hdev, HCI_PERIODIC_INQ)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004233 err = mgmt_cmd_complete(sk, hdev->id,
4234 MGMT_OP_START_SERVICE_DISCOVERY,
4235 MGMT_STATUS_BUSY, &cp->type,
4236 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004237 goto failed;
4238 }
4239
4240 uuid_count = __le16_to_cpu(cp->uuid_count);
4241 if (uuid_count > max_uuid_count) {
4242 BT_ERR("service_discovery: too big uuid_count value %u",
4243 uuid_count);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004244 err = mgmt_cmd_complete(sk, hdev->id,
4245 MGMT_OP_START_SERVICE_DISCOVERY,
4246 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4247 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004248 goto failed;
4249 }
4250
4251 expected_len = sizeof(*cp) + uuid_count * 16;
4252 if (expected_len != len) {
4253 BT_ERR("service_discovery: expected %u bytes, got %u bytes",
4254 expected_len, len);
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004255 err = mgmt_cmd_complete(sk, hdev->id,
4256 MGMT_OP_START_SERVICE_DISCOVERY,
4257 MGMT_STATUS_INVALID_PARAMS, &cp->type,
4258 sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004259 goto failed;
4260 }
4261
4262 cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
Johan Hedberg2922a942014-12-05 13:36:06 +02004263 hdev, data, len);
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004264 if (!cmd) {
4265 err = -ENOMEM;
4266 goto failed;
4267 }
4268
Johan Hedberg2922a942014-12-05 13:36:06 +02004269 cmd->cmd_complete = service_discovery_cmd_complete;
4270
Marcel Holtmann22078802014-12-05 11:45:22 +01004271 /* Clear the discovery filter first to free any previously
4272 * allocated memory for the UUID list.
4273 */
4274 hci_discovery_filter_clear(hdev);
4275
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08004276 hdev->discovery.result_filtering = true;
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004277 hdev->discovery.type = cp->type;
4278 hdev->discovery.rssi = cp->rssi;
4279 hdev->discovery.uuid_count = uuid_count;
4280
4281 if (uuid_count > 0) {
4282 hdev->discovery.uuids = kmemdup(cp->uuids, uuid_count * 16,
4283 GFP_KERNEL);
4284 if (!hdev->discovery.uuids) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004285 err = mgmt_cmd_complete(sk, hdev->id,
4286 MGMT_OP_START_SERVICE_DISCOVERY,
4287 MGMT_STATUS_FAILED,
4288 &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004289 mgmt_pending_remove(cmd);
4290 goto failed;
4291 }
4292 }
4293
4294 hci_req_init(&req, hdev);
4295
4296 if (!trigger_discovery(&req, &status)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004297 err = mgmt_cmd_complete(sk, hdev->id,
4298 MGMT_OP_START_SERVICE_DISCOVERY,
4299 status, &cp->type, sizeof(cp->type));
Jakub Pawlowski66ea9422014-12-05 10:55:59 +01004300 mgmt_pending_remove(cmd);
4301 goto failed;
4302 }
4303
4304 err = hci_req_run(&req, start_discovery_complete);
4305 if (err < 0) {
4306 mgmt_pending_remove(cmd);
4307 goto failed;
4308 }
4309
4310 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
4311
4312failed:
4313 hci_dev_unlock(hdev);
Andre Guedes1183fdc2013-04-30 15:29:35 -03004314 return err;
4315}
4316
Marcel Holtmann1904a852015-01-11 13:50:44 -08004317static void stop_discovery_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Andre Guedes0e05bba2013-04-30 15:29:33 -03004318{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004319 struct mgmt_pending_cmd *cmd;
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004320
Andre Guedes0e05bba2013-04-30 15:29:33 -03004321 BT_DBG("status %d", status);
4322
4323 hci_dev_lock(hdev);
4324
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004325 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
4326 if (cmd) {
Johan Hedberg2922a942014-12-05 13:36:06 +02004327 cmd->cmd_complete(cmd, mgmt_status(status));
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004328 mgmt_pending_remove(cmd);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004329 }
4330
Marcel Holtmann11e6e252014-12-04 11:36:35 +01004331 if (!status)
4332 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004333
Andre Guedes0e05bba2013-04-30 15:29:33 -03004334 hci_dev_unlock(hdev);
4335}
4336
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004337static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004338 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04004339{
Johan Hedbergd9306502012-02-20 23:25:18 +02004340 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004341 struct mgmt_pending_cmd *cmd;
Andre Guedes0e05bba2013-04-30 15:29:33 -03004342 struct hci_request req;
Johan Hedberg14a53662011-04-27 10:29:56 -04004343 int err;
4344
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004345 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04004346
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004347 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004348
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004349 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004350 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4351 MGMT_STATUS_REJECTED, &mgmt_cp->type,
4352 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02004353 goto unlock;
4354 }
4355
4356 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004357 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
4358 MGMT_STATUS_INVALID_PARAMS,
4359 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004360 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02004361 }
4362
Johan Hedberg2922a942014-12-05 13:36:06 +02004363 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04004364 if (!cmd) {
4365 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004366 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04004367 }
4368
Johan Hedberg2922a942014-12-05 13:36:06 +02004369 cmd->cmd_complete = generic_cmd_complete;
4370
Andre Guedes0e05bba2013-04-30 15:29:33 -03004371 hci_req_init(&req, hdev);
4372
Johan Hedberg21a60d32014-06-10 14:05:58 +03004373 hci_stop_discovery(&req);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004374
Johan Hedberg21a60d32014-06-10 14:05:58 +03004375 err = hci_req_run(&req, stop_discovery_complete);
4376 if (!err) {
4377 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Andre Guedes0e05bba2013-04-30 15:29:33 -03004378 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004379 }
4380
Johan Hedberg21a60d32014-06-10 14:05:58 +03004381 mgmt_pending_remove(cmd);
4382
4383 /* If no HCI commands were sent we're done */
4384 if (err == -ENODATA) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004385 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
4386 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg21a60d32014-06-10 14:05:58 +03004387 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
4388 }
Johan Hedberg14a53662011-04-27 10:29:56 -04004389
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004390unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004391 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04004392 return err;
4393}
4394
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004395static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004396 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02004397{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004398 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004399 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02004400 int err;
4401
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004402 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004403
Johan Hedberg561aafb2012-01-04 13:31:59 +02004404 hci_dev_lock(hdev);
4405
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004406 if (!hci_discovery_active(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004407 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4408 MGMT_STATUS_FAILED, &cp->addr,
4409 sizeof(cp->addr));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02004410 goto failed;
4411 }
4412
Johan Hedberga198e7b2012-02-17 14:27:06 +02004413 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004414 if (!e) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004415 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
4416 MGMT_STATUS_INVALID_PARAMS, &cp->addr,
4417 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004418 goto failed;
4419 }
4420
4421 if (cp->name_known) {
4422 e->name_state = NAME_KNOWN;
4423 list_del(&e->list);
4424 } else {
4425 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02004426 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004427 }
4428
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004429 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0,
4430 &cp->addr, sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02004431
4432failed:
4433 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02004434 return err;
4435}
4436
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004437static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004438 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004439{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004440 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004441 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004442 int err;
4443
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004444 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004445
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004446 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004447 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
4448 MGMT_STATUS_INVALID_PARAMS,
4449 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004450
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004451 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004452
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004453 err = hci_bdaddr_list_add(&hdev->blacklist, &cp->addr.bdaddr,
4454 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004455 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004456 status = MGMT_STATUS_FAILED;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004457 goto done;
4458 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004459
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004460 mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4461 sk);
4462 status = MGMT_STATUS_SUCCESS;
4463
4464done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004465 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
4466 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004467
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004468 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004469
4470 return err;
4471}
4472
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004473static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004474 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03004475{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004476 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004477 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03004478 int err;
4479
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004480 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03004481
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004482 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004483 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
4484 MGMT_STATUS_INVALID_PARAMS,
4485 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004486
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004487 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004488
Johan Hedbergdcc36c12014-07-09 12:59:13 +03004489 err = hci_bdaddr_list_del(&hdev->blacklist, &cp->addr.bdaddr,
4490 cp->addr.type);
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004491 if (err < 0) {
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004492 status = MGMT_STATUS_INVALID_PARAMS;
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004493 goto done;
4494 }
Johan Hedbergf0eeea82012-02-19 12:58:54 +02004495
Johan Hedberg2a8357f2014-07-01 22:09:47 +03004496 mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &cp->addr, sizeof(cp->addr),
4497 sk);
4498 status = MGMT_STATUS_SUCCESS;
4499
4500done:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004501 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
4502 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03004503
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03004504 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03004505
4506 return err;
4507}
4508
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004509static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
4510 u16 len)
4511{
4512 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05004513 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004514 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01004515 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004516
4517 BT_DBG("%s", hdev->name);
4518
Szymon Jancc72d4b82012-03-16 16:02:57 +01004519 source = __le16_to_cpu(cp->source);
4520
4521 if (source > 0x0002)
Johan Hedberga69e8372015-03-06 21:08:53 +02004522 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
4523 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc72d4b82012-03-16 16:02:57 +01004524
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004525 hci_dev_lock(hdev);
4526
Szymon Jancc72d4b82012-03-16 16:02:57 +01004527 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004528 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
4529 hdev->devid_product = __le16_to_cpu(cp->product);
4530 hdev->devid_version = __le16_to_cpu(cp->version);
4531
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004532 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0,
4533 NULL, 0);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004534
Johan Hedberg890ea892013-03-15 17:06:52 -05004535 hci_req_init(&req, hdev);
4536 update_eir(&req);
4537 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004538
4539 hci_dev_unlock(hdev);
4540
4541 return err;
4542}
4543
Marcel Holtmann1904a852015-01-11 13:50:44 -08004544static void set_advertising_complete(struct hci_dev *hdev, u8 status,
4545 u16 opcode)
Johan Hedberg4375f102013-09-25 13:26:10 +03004546{
4547 struct cmd_lookup match = { NULL, hdev };
4548
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304549 hci_dev_lock(hdev);
4550
Johan Hedberg4375f102013-09-25 13:26:10 +03004551 if (status) {
4552 u8 mgmt_err = mgmt_status(status);
4553
4554 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
4555 cmd_status_rsp, &mgmt_err);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304556 goto unlock;
Johan Hedberg4375f102013-09-25 13:26:10 +03004557 }
4558
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004559 if (hci_dev_test_flag(hdev, HCI_LE_ADV))
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004560 hci_dev_set_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004561 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004562 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
Johan Hedbergc93bd152014-07-08 15:07:48 +03004563
Johan Hedberg4375f102013-09-25 13:26:10 +03004564 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
4565 &match);
4566
4567 new_settings(hdev, match.sk);
4568
4569 if (match.sk)
4570 sock_put(match.sk);
Jaganath Kanakkassery3ad67582014-12-11 11:43:12 +05304571
4572unlock:
4573 hci_dev_unlock(hdev);
Johan Hedberg4375f102013-09-25 13:26:10 +03004574}
4575
Marcel Holtmann21b51872013-10-10 09:47:53 -07004576static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
4577 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03004578{
4579 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004580 struct mgmt_pending_cmd *cmd;
Johan Hedberg4375f102013-09-25 13:26:10 +03004581 struct hci_request req;
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004582 u8 val, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03004583 int err;
4584
4585 BT_DBG("request for %s", hdev->name);
4586
Johan Hedberge6fe7982013-10-02 15:45:22 +03004587 status = mgmt_le_support(hdev);
4588 if (status)
Johan Hedberga69e8372015-03-06 21:08:53 +02004589 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4590 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03004591
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004592 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02004593 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4594 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg4375f102013-09-25 13:26:10 +03004595
4596 hci_dev_lock(hdev);
4597
4598 val = !!cp->val;
Johan Hedberg4375f102013-09-25 13:26:10 +03004599
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02004600 /* The following conditions are ones which mean that we should
4601 * not do any HCI communication but directly send a mgmt
4602 * response to user space (after toggling the flag if
4603 * necessary).
4604 */
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004605 if (!hdev_is_powered(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004606 (val == hci_dev_test_flag(hdev, HCI_ADVERTISING) &&
4607 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) ||
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004608 hci_conn_num(hdev, LE_LINK) > 0 ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004609 (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Johan Hedberge8bb6b92014-07-08 15:07:53 +03004610 hdev->le_scan_type == LE_SCAN_ACTIVE)) {
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004611 bool changed;
Johan Hedberg4375f102013-09-25 13:26:10 +03004612
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004613 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07004614 changed = !hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004615 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004616 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004617 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004618 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004619 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07004620 changed = hci_dev_test_and_clear_flag(hdev, HCI_ADVERTISING);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004621 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Johan Hedberg4375f102013-09-25 13:26:10 +03004622 }
4623
4624 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
4625 if (err < 0)
4626 goto unlock;
4627
4628 if (changed)
4629 err = new_settings(hdev, sk);
4630
4631 goto unlock;
4632 }
4633
4634 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
4635 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004636 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
4637 MGMT_STATUS_BUSY);
Johan Hedberg4375f102013-09-25 13:26:10 +03004638 goto unlock;
4639 }
4640
4641 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
4642 if (!cmd) {
4643 err = -ENOMEM;
4644 goto unlock;
4645 }
4646
4647 hci_req_init(&req, hdev);
4648
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004649 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004650 hci_dev_set_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004651 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004652 hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE);
Marcel Holtmanncc91cb02015-03-12 22:30:58 -07004653
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004654 if (val)
4655 enable_advertising(&req);
4656 else
4657 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03004658
4659 err = hci_req_run(&req, set_advertising_complete);
4660 if (err < 0)
4661 mgmt_pending_remove(cmd);
4662
4663unlock:
4664 hci_dev_unlock(hdev);
4665 return err;
4666}
4667
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004668static int set_static_address(struct sock *sk, struct hci_dev *hdev,
4669 void *data, u16 len)
4670{
4671 struct mgmt_cp_set_static_address *cp = data;
4672 int err;
4673
4674 BT_DBG("%s", hdev->name);
4675
Marcel Holtmann62af4442013-10-02 22:10:32 -07004676 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004677 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4678 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004679
4680 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004681 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
4682 MGMT_STATUS_REJECTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004683
4684 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
4685 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
Johan Hedberga69e8372015-03-06 21:08:53 +02004686 return mgmt_cmd_status(sk, hdev->id,
4687 MGMT_OP_SET_STATIC_ADDRESS,
4688 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004689
4690 /* Two most significant bits shall be set */
4691 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
Johan Hedberga69e8372015-03-06 21:08:53 +02004692 return mgmt_cmd_status(sk, hdev->id,
4693 MGMT_OP_SET_STATIC_ADDRESS,
4694 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004695 }
4696
4697 hci_dev_lock(hdev);
4698
4699 bacpy(&hdev->static_addr, &cp->bdaddr);
4700
Marcel Holtmann93690c22015-03-06 10:11:21 -08004701 err = send_settings_rsp(sk, MGMT_OP_SET_STATIC_ADDRESS, hdev);
4702 if (err < 0)
4703 goto unlock;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004704
Marcel Holtmann93690c22015-03-06 10:11:21 -08004705 err = new_settings(hdev, sk);
4706
4707unlock:
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004708 hci_dev_unlock(hdev);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004709 return err;
4710}
4711
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004712static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
4713 void *data, u16 len)
4714{
4715 struct mgmt_cp_set_scan_params *cp = data;
4716 __u16 interval, window;
4717 int err;
4718
4719 BT_DBG("%s", hdev->name);
4720
4721 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004722 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4723 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004724
4725 interval = __le16_to_cpu(cp->interval);
4726
4727 if (interval < 0x0004 || interval > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004728 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4729 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004730
4731 window = __le16_to_cpu(cp->window);
4732
4733 if (window < 0x0004 || window > 0x4000)
Johan Hedberga69e8372015-03-06 21:08:53 +02004734 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4735 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004736
Marcel Holtmann899e1072013-10-14 09:55:32 -07004737 if (window > interval)
Johan Hedberga69e8372015-03-06 21:08:53 +02004738 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
4739 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann899e1072013-10-14 09:55:32 -07004740
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004741 hci_dev_lock(hdev);
4742
4743 hdev->le_scan_interval = interval;
4744 hdev->le_scan_window = window;
4745
Johan Hedberg2a1afb52015-03-06 21:08:54 +02004746 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0,
4747 NULL, 0);
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004748
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004749 /* If background scan is running, restart it so new parameters are
4750 * loaded.
4751 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004752 if (hci_dev_test_flag(hdev, HCI_LE_SCAN) &&
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03004753 hdev->discovery.state == DISCOVERY_STOPPED) {
4754 struct hci_request req;
4755
4756 hci_req_init(&req, hdev);
4757
4758 hci_req_add_le_scan_disable(&req);
4759 hci_req_add_le_passive_scan(&req);
4760
4761 hci_req_run(&req, NULL);
4762 }
4763
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004764 hci_dev_unlock(hdev);
4765
4766 return err;
4767}
4768
Marcel Holtmann1904a852015-01-11 13:50:44 -08004769static void fast_connectable_complete(struct hci_dev *hdev, u8 status,
4770 u16 opcode)
Johan Hedberg33e38b32013-03-15 17:07:05 -05004771{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004772 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004773
4774 BT_DBG("status 0x%02x", status);
4775
4776 hci_dev_lock(hdev);
4777
4778 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4779 if (!cmd)
4780 goto unlock;
4781
4782 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004783 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4784 mgmt_status(status));
Johan Hedberg33e38b32013-03-15 17:07:05 -05004785 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004786 struct mgmt_mode *cp = cmd->param;
4787
4788 if (cp->val)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004789 hci_dev_set_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004790 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004791 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004792
Johan Hedberg33e38b32013-03-15 17:07:05 -05004793 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
4794 new_settings(hdev, cmd->sk);
4795 }
4796
4797 mgmt_pending_remove(cmd);
4798
4799unlock:
4800 hci_dev_unlock(hdev);
4801}
4802
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004803static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004804 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03004805{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004806 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004807 struct mgmt_pending_cmd *cmd;
Johan Hedberg33e38b32013-03-15 17:07:05 -05004808 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03004809 int err;
4810
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004811 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004812
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004813 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) ||
Johan Hedberg56f87902013-10-02 13:43:13 +03004814 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberga69e8372015-03-06 21:08:53 +02004815 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4816 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03004817
Johan Hedberga7e80f22013-01-09 16:05:19 +02004818 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004819 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4820 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga7e80f22013-01-09 16:05:19 +02004821
Antti Julkuf6422ec2011-06-22 13:11:56 +03004822 hci_dev_lock(hdev);
4823
Johan Hedberg05cbf292013-03-15 17:07:07 -05004824 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004825 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4826 MGMT_STATUS_BUSY);
Johan Hedberg05cbf292013-03-15 17:07:07 -05004827 goto unlock;
4828 }
4829
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004830 if (!!cp->val == hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE)) {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004831 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4832 hdev);
4833 goto unlock;
4834 }
4835
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004836 if (!hdev_is_powered(hdev)) {
Marcel Holtmannce05d602015-03-13 02:11:03 -07004837 hci_dev_change_flag(hdev, HCI_FAST_CONNECTABLE);
Johan Hedberg406ef2a2015-03-10 20:14:27 +02004838 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4839 hdev);
4840 new_settings(hdev, sk);
4841 goto unlock;
4842 }
4843
Johan Hedberg33e38b32013-03-15 17:07:05 -05004844 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4845 data, len);
4846 if (!cmd) {
4847 err = -ENOMEM;
4848 goto unlock;
4849 }
4850
4851 hci_req_init(&req, hdev);
4852
Johan Hedberg406d7802013-03-15 17:07:09 -05004853 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004854
4855 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004856 if (err < 0) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004857 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4858 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004859 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004860 }
4861
Johan Hedberg33e38b32013-03-15 17:07:05 -05004862unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004863 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004864
Antti Julkuf6422ec2011-06-22 13:11:56 +03004865 return err;
4866}
4867
Marcel Holtmann1904a852015-01-11 13:50:44 -08004868static void set_bredr_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg0663ca22013-10-02 13:43:14 +03004869{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004870 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004871
4872 BT_DBG("status 0x%02x", status);
4873
4874 hci_dev_lock(hdev);
4875
4876 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
4877 if (!cmd)
4878 goto unlock;
4879
4880 if (status) {
4881 u8 mgmt_err = mgmt_status(status);
4882
4883 /* We need to restore the flag if related HCI commands
4884 * failed.
4885 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004886 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004887
Johan Hedberga69e8372015-03-06 21:08:53 +02004888 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004889 } else {
4890 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4891 new_settings(hdev, cmd->sk);
4892 }
4893
4894 mgmt_pending_remove(cmd);
4895
4896unlock:
4897 hci_dev_unlock(hdev);
4898}
4899
4900static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4901{
4902 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02004903 struct mgmt_pending_cmd *cmd;
Johan Hedberg0663ca22013-10-02 13:43:14 +03004904 struct hci_request req;
4905 int err;
4906
4907 BT_DBG("request for %s", hdev->name);
4908
4909 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02004910 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4911 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004912
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004913 if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02004914 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4915 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004916
4917 if (cp->val != 0x00 && cp->val != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02004918 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4919 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004920
4921 hci_dev_lock(hdev);
4922
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004923 if (cp->val == hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004924 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4925 goto unlock;
4926 }
4927
4928 if (!hdev_is_powered(hdev)) {
4929 if (!cp->val) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07004930 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
4931 hci_dev_clear_flag(hdev, HCI_SSP_ENABLED);
4932 hci_dev_clear_flag(hdev, HCI_LINK_SECURITY);
4933 hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE);
4934 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004935 }
4936
Marcel Holtmannce05d602015-03-13 02:11:03 -07004937 hci_dev_change_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004938
4939 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4940 if (err < 0)
4941 goto unlock;
4942
4943 err = new_settings(hdev, sk);
4944 goto unlock;
4945 }
4946
4947 /* Reject disabling when powered on */
4948 if (!cp->val) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004949 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4950 MGMT_STATUS_REJECTED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004951 goto unlock;
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004952 } else {
4953 /* When configuring a dual-mode controller to operate
4954 * with LE only and using a static address, then switching
4955 * BR/EDR back on is not allowed.
4956 *
4957 * Dual-mode controllers shall operate with the public
4958 * address as its identity address for BR/EDR and LE. So
4959 * reject the attempt to create an invalid configuration.
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004960 *
4961 * The same restrictions applies when secure connections
4962 * has been enabled. For BR/EDR this is a controller feature
4963 * while for LE it is a host stack feature. This means that
4964 * switching BR/EDR back on when secure connections has been
4965 * enabled is not a supported transaction.
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004966 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004967 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Marcel Holtmann3a5486e2015-01-22 11:15:21 -08004968 (bacmp(&hdev->static_addr, BDADDR_ANY) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07004969 hci_dev_test_flag(hdev, HCI_SC_ENABLED))) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004970 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4971 MGMT_STATUS_REJECTED);
Marcel Holtmann111e4bc2015-01-14 14:40:42 -08004972 goto unlock;
4973 }
Johan Hedberg0663ca22013-10-02 13:43:14 +03004974 }
4975
4976 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02004977 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4978 MGMT_STATUS_BUSY);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004979 goto unlock;
4980 }
4981
4982 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4983 if (!cmd) {
4984 err = -ENOMEM;
4985 goto unlock;
4986 }
4987
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004988 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03004989 * generates the correct flags.
4990 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07004991 hci_dev_set_flag(hdev, HCI_BREDR_ENABLED);
Johan Hedberg0663ca22013-10-02 13:43:14 +03004992
4993 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004994
Johan Hedberg432df052014-08-01 11:13:31 +03004995 write_fast_connectable(&req, false);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02004996 __hci_update_page_scan(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004997
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004998 /* Since only the advertising data flags will change, there
4999 * is no need to update the scan response data.
5000 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07005001 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03005002
Johan Hedberg0663ca22013-10-02 13:43:14 +03005003 err = hci_req_run(&req, set_bredr_complete);
5004 if (err < 0)
5005 mgmt_pending_remove(cmd);
5006
5007unlock:
5008 hci_dev_unlock(hdev);
5009 return err;
5010}
5011
Johan Hedberga1443f52015-01-23 15:42:46 +02005012static void sc_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
5013{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005014 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005015 struct mgmt_mode *cp;
5016
5017 BT_DBG("%s status %u", hdev->name, status);
5018
5019 hci_dev_lock(hdev);
5020
5021 cmd = mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev);
5022 if (!cmd)
5023 goto unlock;
5024
5025 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005026 mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
5027 mgmt_status(status));
Johan Hedberga1443f52015-01-23 15:42:46 +02005028 goto remove;
5029 }
5030
5031 cp = cmd->param;
5032
5033 switch (cp->val) {
5034 case 0x00:
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005035 hci_dev_clear_flag(hdev, HCI_SC_ENABLED);
5036 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005037 break;
5038 case 0x01:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005039 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005040 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005041 break;
5042 case 0x02:
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005043 hci_dev_set_flag(hdev, HCI_SC_ENABLED);
5044 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Johan Hedberga1443f52015-01-23 15:42:46 +02005045 break;
5046 }
5047
5048 send_settings_rsp(cmd->sk, MGMT_OP_SET_SECURE_CONN, hdev);
5049 new_settings(hdev, cmd->sk);
5050
5051remove:
5052 mgmt_pending_remove(cmd);
5053unlock:
5054 hci_dev_unlock(hdev);
5055}
5056
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005057static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
5058 void *data, u16 len)
5059{
5060 struct mgmt_mode *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005061 struct mgmt_pending_cmd *cmd;
Johan Hedberga1443f52015-01-23 15:42:46 +02005062 struct hci_request req;
Johan Hedberga3209692014-05-26 11:23:35 +03005063 u8 val;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005064 int err;
5065
5066 BT_DBG("request for %s", hdev->name);
5067
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005068 if (!lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005069 !hci_dev_test_flag(hdev, HCI_LE_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005070 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5071 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005072
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005073 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
Johan Hedberg59200282015-01-28 19:56:00 +02005074 lmp_sc_capable(hdev) &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005075 !hci_dev_test_flag(hdev, HCI_SSP_ENABLED))
Johan Hedberga69e8372015-03-06 21:08:53 +02005076 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5077 MGMT_STATUS_REJECTED);
Marcel Holtmanned93ec62015-01-22 11:15:22 -08005078
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005079 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005080 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005081 MGMT_STATUS_INVALID_PARAMS);
5082
5083 hci_dev_lock(hdev);
5084
Marcel Holtmann05b3c3e2014-12-31 14:43:18 -08005085 if (!hdev_is_powered(hdev) || !lmp_sc_capable(hdev) ||
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005086 !hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005087 bool changed;
5088
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005089 if (cp->val) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005090 changed = !hci_dev_test_and_set_flag(hdev,
5091 HCI_SC_ENABLED);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005092 if (cp->val == 0x02)
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005093 hci_dev_set_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005094 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005095 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005096 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005097 changed = hci_dev_test_and_clear_flag(hdev,
5098 HCI_SC_ENABLED);
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005099 hci_dev_clear_flag(hdev, HCI_SC_ONLY);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005100 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005101
5102 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5103 if (err < 0)
5104 goto failed;
5105
5106 if (changed)
5107 err = new_settings(hdev, sk);
5108
5109 goto failed;
5110 }
5111
5112 if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02005113 err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
5114 MGMT_STATUS_BUSY);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005115 goto failed;
5116 }
5117
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005118 val = !!cp->val;
5119
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005120 if (val == hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
5121 (cp->val == 0x02) == hci_dev_test_flag(hdev, HCI_SC_ONLY)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005122 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
5123 goto failed;
5124 }
5125
5126 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
5127 if (!cmd) {
5128 err = -ENOMEM;
5129 goto failed;
5130 }
5131
Johan Hedberga1443f52015-01-23 15:42:46 +02005132 hci_req_init(&req, hdev);
5133 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
5134 err = hci_req_run(&req, sc_enable_complete);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005135 if (err < 0) {
5136 mgmt_pending_remove(cmd);
5137 goto failed;
5138 }
5139
5140failed:
5141 hci_dev_unlock(hdev);
5142 return err;
5143}
5144
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005145static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
5146 void *data, u16 len)
5147{
5148 struct mgmt_mode *cp = data;
Johan Hedbergb97109792014-06-24 14:00:28 +03005149 bool changed, use_changed;
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005150 int err;
5151
5152 BT_DBG("request for %s", hdev->name);
5153
Johan Hedbergb97109792014-06-24 14:00:28 +03005154 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga69e8372015-03-06 21:08:53 +02005155 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
5156 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005157
5158 hci_dev_lock(hdev);
5159
5160 if (cp->val)
Marcel Holtmann238be782015-03-13 02:11:06 -07005161 changed = !hci_dev_test_and_set_flag(hdev, HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005162 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005163 changed = hci_dev_test_and_clear_flag(hdev,
5164 HCI_KEEP_DEBUG_KEYS);
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005165
Johan Hedbergb97109792014-06-24 14:00:28 +03005166 if (cp->val == 0x02)
Marcel Holtmann238be782015-03-13 02:11:06 -07005167 use_changed = !hci_dev_test_and_set_flag(hdev,
5168 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005169 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005170 use_changed = hci_dev_test_and_clear_flag(hdev,
5171 HCI_USE_DEBUG_KEYS);
Johan Hedbergb97109792014-06-24 14:00:28 +03005172
5173 if (hdev_is_powered(hdev) && use_changed &&
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07005174 hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
Johan Hedbergb97109792014-06-24 14:00:28 +03005175 u8 mode = (cp->val == 0x02) ? 0x01 : 0x00;
5176 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_DEBUG_MODE,
5177 sizeof(mode), &mode);
5178 }
5179
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08005180 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
5181 if (err < 0)
5182 goto unlock;
5183
5184 if (changed)
5185 err = new_settings(hdev, sk);
5186
5187unlock:
5188 hci_dev_unlock(hdev);
5189 return err;
5190}
5191
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005192static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5193 u16 len)
5194{
5195 struct mgmt_cp_set_privacy *cp = cp_data;
5196 bool changed;
5197 int err;
5198
5199 BT_DBG("request for %s", hdev->name);
5200
5201 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005202 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5203 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005204
5205 if (cp->privacy != 0x00 && cp->privacy != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02005206 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5207 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005208
5209 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005210 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
5211 MGMT_STATUS_REJECTED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005212
5213 hci_dev_lock(hdev);
5214
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005215 /* If user space supports this command it is also expected to
5216 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
5217 */
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005218 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02005219
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005220 if (cp->privacy) {
Marcel Holtmann238be782015-03-13 02:11:06 -07005221 changed = !hci_dev_test_and_set_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005222 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005223 hci_dev_set_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005224 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07005225 changed = hci_dev_test_and_clear_flag(hdev, HCI_PRIVACY);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005226 memset(hdev->irk, 0, sizeof(hdev->irk));
Marcel Holtmanna358dc12015-03-13 02:11:02 -07005227 hci_dev_clear_flag(hdev, HCI_RPA_EXPIRED);
Johan Hedberg62b04cd2014-02-23 19:42:27 +02005228 }
5229
5230 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
5231 if (err < 0)
5232 goto unlock;
5233
5234 if (changed)
5235 err = new_settings(hdev, sk);
5236
5237unlock:
5238 hci_dev_unlock(hdev);
5239 return err;
5240}
5241
Johan Hedberg41edf162014-02-18 10:19:35 +02005242static bool irk_is_valid(struct mgmt_irk_info *irk)
5243{
5244 switch (irk->addr.type) {
5245 case BDADDR_LE_PUBLIC:
5246 return true;
5247
5248 case BDADDR_LE_RANDOM:
5249 /* Two most significant bits shall be set */
5250 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5251 return false;
5252 return true;
5253 }
5254
5255 return false;
5256}
5257
5258static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
5259 u16 len)
5260{
5261 struct mgmt_cp_load_irks *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005262 const u16 max_irk_count = ((U16_MAX - sizeof(*cp)) /
5263 sizeof(struct mgmt_irk_info));
Johan Hedberg41edf162014-02-18 10:19:35 +02005264 u16 irk_count, expected_len;
5265 int i, err;
5266
5267 BT_DBG("request for %s", hdev->name);
5268
5269 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005270 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5271 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg41edf162014-02-18 10:19:35 +02005272
5273 irk_count = __le16_to_cpu(cp->irk_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005274 if (irk_count > max_irk_count) {
5275 BT_ERR("load_irks: too big irk_count value %u", irk_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005276 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5277 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005278 }
Johan Hedberg41edf162014-02-18 10:19:35 +02005279
5280 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
5281 if (expected_len != len) {
5282 BT_ERR("load_irks: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02005283 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005284 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
5285 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005286 }
5287
5288 BT_DBG("%s irk_count %u", hdev->name, irk_count);
5289
5290 for (i = 0; i < irk_count; i++) {
5291 struct mgmt_irk_info *key = &cp->irks[i];
5292
5293 if (!irk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005294 return mgmt_cmd_status(sk, hdev->id,
5295 MGMT_OP_LOAD_IRKS,
5296 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg41edf162014-02-18 10:19:35 +02005297 }
5298
5299 hci_dev_lock(hdev);
5300
5301 hci_smp_irks_clear(hdev);
5302
5303 for (i = 0; i < irk_count; i++) {
5304 struct mgmt_irk_info *irk = &cp->irks[i];
5305 u8 addr_type;
5306
5307 if (irk->addr.type == BDADDR_LE_PUBLIC)
5308 addr_type = ADDR_LE_DEV_PUBLIC;
5309 else
5310 addr_type = ADDR_LE_DEV_RANDOM;
5311
5312 hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
5313 BDADDR_ANY);
5314 }
5315
Marcel Holtmanna1536da2015-03-13 02:11:01 -07005316 hci_dev_set_flag(hdev, HCI_RPA_RESOLVING);
Johan Hedberg41edf162014-02-18 10:19:35 +02005317
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005318 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
Johan Hedberg41edf162014-02-18 10:19:35 +02005319
5320 hci_dev_unlock(hdev);
5321
5322 return err;
5323}
5324
Johan Hedberg3f706b72013-01-20 14:27:16 +02005325static bool ltk_is_valid(struct mgmt_ltk_info *key)
5326{
5327 if (key->master != 0x00 && key->master != 0x01)
5328 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08005329
5330 switch (key->addr.type) {
5331 case BDADDR_LE_PUBLIC:
5332 return true;
5333
5334 case BDADDR_LE_RANDOM:
5335 /* Two most significant bits shall be set */
5336 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
5337 return false;
5338 return true;
5339 }
5340
5341 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02005342}
5343
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005344static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005345 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005346{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005347 struct mgmt_cp_load_long_term_keys *cp = cp_data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03005348 const u16 max_key_count = ((U16_MAX - sizeof(*cp)) /
5349 sizeof(struct mgmt_ltk_info));
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005350 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005351 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005352
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005353 BT_DBG("request for %s", hdev->name);
5354
5355 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02005356 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5357 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07005358
Marcel Holtmann1f350c82012-03-12 20:31:08 -07005359 key_count = __le16_to_cpu(cp->key_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005360 if (key_count > max_key_count) {
5361 BT_ERR("load_ltks: too big key_count value %u", key_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02005362 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5363 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03005364 }
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005365
5366 expected_len = sizeof(*cp) + key_count *
5367 sizeof(struct mgmt_ltk_info);
5368 if (expected_len != len) {
5369 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Johan Hedberg2606ecb2014-03-07 15:04:13 +02005370 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02005371 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
5372 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005373 }
5374
Johan Hedbergbdb6d972012-02-28 06:13:32 +02005375 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005376
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005377 for (i = 0; i < key_count; i++) {
5378 struct mgmt_ltk_info *key = &cp->keys[i];
5379
Johan Hedberg3f706b72013-01-20 14:27:16 +02005380 if (!ltk_is_valid(key))
Johan Hedberga69e8372015-03-06 21:08:53 +02005381 return mgmt_cmd_status(sk, hdev->id,
5382 MGMT_OP_LOAD_LONG_TERM_KEYS,
5383 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg54ad6d82013-01-20 14:27:15 +02005384 }
5385
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005386 hci_dev_lock(hdev);
5387
5388 hci_smp_ltks_clear(hdev);
5389
5390 for (i = 0; i < key_count; i++) {
5391 struct mgmt_ltk_info *key = &cp->keys[i];
Johan Hedbergd7b25452014-05-23 13:19:53 +03005392 u8 type, addr_type, authenticated;
Marcel Holtmann79d95a12013-10-13 03:57:38 -07005393
5394 if (key->addr.type == BDADDR_LE_PUBLIC)
5395 addr_type = ADDR_LE_DEV_PUBLIC;
5396 else
5397 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005398
Johan Hedberg61b43352014-05-29 19:36:53 +03005399 switch (key->type) {
5400 case MGMT_LTK_UNAUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005401 authenticated = 0x00;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005402 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005403 break;
5404 case MGMT_LTK_AUTHENTICATED:
Johan Hedbergd7b25452014-05-23 13:19:53 +03005405 authenticated = 0x01;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005406 type = key->master ? SMP_LTK : SMP_LTK_SLAVE;
Johan Hedberg61b43352014-05-29 19:36:53 +03005407 break;
Johan Hedberg23fb8de2014-05-23 13:15:37 +03005408 case MGMT_LTK_P256_UNAUTH:
5409 authenticated = 0x00;
5410 type = SMP_LTK_P256;
5411 break;
5412 case MGMT_LTK_P256_AUTH:
5413 authenticated = 0x01;
5414 type = SMP_LTK_P256;
5415 break;
5416 case MGMT_LTK_P256_DEBUG:
5417 authenticated = 0x00;
5418 type = SMP_LTK_P256_DEBUG;
Johan Hedberg61b43352014-05-29 19:36:53 +03005419 default:
5420 continue;
5421 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03005422
Johan Hedberg35d70272014-02-19 14:57:47 +02005423 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type,
Johan Hedbergd7b25452014-05-23 13:19:53 +03005424 authenticated, key->val, key->enc_size, key->ediv,
Johan Hedberg35d70272014-02-19 14:57:47 +02005425 key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005426 }
5427
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005428 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005429 NULL, 0);
5430
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005431 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005432
Johan Hedberg715a5bf2013-01-09 15:29:34 +02005433 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005434}
5435
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005436static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005437{
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005438 struct hci_conn *conn = cmd->user_data;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005439 struct mgmt_rp_get_conn_info rp;
Johan Hedberg9df74652014-12-19 22:26:03 +02005440 int err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005441
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005442 memcpy(&rp.addr, cmd->param, sizeof(rp.addr));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005443
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005444 if (status == MGMT_STATUS_SUCCESS) {
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005445 rp.rssi = conn->rssi;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005446 rp.tx_power = conn->tx_power;
5447 rp.max_tx_power = conn->max_tx_power;
5448 } else {
5449 rp.rssi = HCI_RSSI_INVALID;
5450 rp.tx_power = HCI_TX_POWER_INVALID;
5451 rp.max_tx_power = HCI_TX_POWER_INVALID;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005452 }
5453
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005454 err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO,
5455 status, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005456
5457 hci_conn_drop(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005458 hci_conn_put(conn);
Johan Hedberg9df74652014-12-19 22:26:03 +02005459
5460 return err;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005461}
5462
Marcel Holtmann1904a852015-01-11 13:50:44 -08005463static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status,
5464 u16 opcode)
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005465{
5466 struct hci_cp_read_rssi *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005467 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005468 struct hci_conn *conn;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005469 u16 handle;
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005470 u8 status;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005471
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005472 BT_DBG("status 0x%02x", hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005473
5474 hci_dev_lock(hdev);
5475
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005476 /* Commands sent in request are either Read RSSI or Read Transmit Power
5477 * Level so we check which one was last sent to retrieve connection
5478 * handle. Both commands have handle as first parameter so it's safe to
5479 * cast data on the same command struct.
5480 *
5481 * First command sent is always Read RSSI and we fail only if it fails.
5482 * In other case we simply override error to indicate success as we
5483 * already remembered if TX power value is actually valid.
5484 */
5485 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI);
5486 if (!cp) {
5487 cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005488 status = MGMT_STATUS_SUCCESS;
5489 } else {
5490 status = mgmt_status(hci_status);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005491 }
5492
5493 if (!cp) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005494 BT_ERR("invalid sent_cmd in conn_info response");
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005495 goto unlock;
5496 }
5497
5498 handle = __le16_to_cpu(cp->handle);
5499 conn = hci_conn_hash_lookup_handle(hdev, handle);
5500 if (!conn) {
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005501 BT_ERR("unknown handle (%d) in conn_info response", handle);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005502 goto unlock;
5503 }
5504
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005505 cmd = mgmt_pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn);
5506 if (!cmd)
5507 goto unlock;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005508
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005509 cmd->cmd_complete(cmd, status);
5510 mgmt_pending_remove(cmd);
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005511
5512unlock:
5513 hci_dev_unlock(hdev);
5514}
5515
5516static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data,
5517 u16 len)
5518{
5519 struct mgmt_cp_get_conn_info *cp = data;
5520 struct mgmt_rp_get_conn_info rp;
5521 struct hci_conn *conn;
5522 unsigned long conn_info_age;
5523 int err = 0;
5524
5525 BT_DBG("%s", hdev->name);
5526
5527 memset(&rp, 0, sizeof(rp));
5528 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5529 rp.addr.type = cp->addr.type;
5530
5531 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005532 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5533 MGMT_STATUS_INVALID_PARAMS,
5534 &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005535
5536 hci_dev_lock(hdev);
5537
5538 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005539 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5540 MGMT_STATUS_NOT_POWERED, &rp,
5541 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005542 goto unlock;
5543 }
5544
5545 if (cp->addr.type == BDADDR_BREDR)
5546 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5547 &cp->addr.bdaddr);
5548 else
5549 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
5550
5551 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005552 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5553 MGMT_STATUS_NOT_CONNECTED, &rp,
5554 sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005555 goto unlock;
5556 }
5557
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005558 if (mgmt_pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005559 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5560 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005561 goto unlock;
5562 }
5563
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005564 /* To avoid client trying to guess when to poll again for information we
5565 * calculate conn info age as random value between min/max set in hdev.
5566 */
5567 conn_info_age = hdev->conn_info_min_age +
5568 prandom_u32_max(hdev->conn_info_max_age -
5569 hdev->conn_info_min_age);
5570
5571 /* Query controller to refresh cached values if they are too old or were
5572 * never read.
5573 */
Andrzej Kaczmarekf4e2dd52014-05-16 16:48:57 +02005574 if (time_after(jiffies, conn->conn_info_timestamp +
5575 msecs_to_jiffies(conn_info_age)) ||
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005576 !conn->conn_info_timestamp) {
5577 struct hci_request req;
5578 struct hci_cp_read_tx_power req_txp_cp;
5579 struct hci_cp_read_rssi req_rssi_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005580 struct mgmt_pending_cmd *cmd;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005581
5582 hci_req_init(&req, hdev);
5583 req_rssi_cp.handle = cpu_to_le16(conn->handle);
5584 hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp),
5585 &req_rssi_cp);
5586
Andrzej Kaczmarekf7faab02014-05-14 13:43:04 +02005587 /* For LE links TX power does not change thus we don't need to
5588 * query for it once value is known.
5589 */
5590 if (!bdaddr_type_is_le(cp->addr.type) ||
5591 conn->tx_power == HCI_TX_POWER_INVALID) {
5592 req_txp_cp.handle = cpu_to_le16(conn->handle);
5593 req_txp_cp.type = 0x00;
5594 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5595 sizeof(req_txp_cp), &req_txp_cp);
5596 }
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005597
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005598 /* Max TX power needs to be read only once per connection */
5599 if (conn->max_tx_power == HCI_TX_POWER_INVALID) {
5600 req_txp_cp.handle = cpu_to_le16(conn->handle);
5601 req_txp_cp.type = 0x01;
5602 hci_req_add(&req, HCI_OP_READ_TX_POWER,
5603 sizeof(req_txp_cp), &req_txp_cp);
5604 }
5605
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005606 err = hci_req_run(&req, conn_info_refresh_complete);
5607 if (err < 0)
5608 goto unlock;
5609
5610 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev,
5611 data, len);
5612 if (!cmd) {
5613 err = -ENOMEM;
5614 goto unlock;
5615 }
5616
5617 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005618 cmd->user_data = hci_conn_get(conn);
Johan Hedberg9981bdb2014-12-05 13:42:57 +02005619 cmd->cmd_complete = conn_info_cmd_complete;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005620
5621 conn->conn_info_timestamp = jiffies;
5622 } else {
5623 /* Cache is valid, just reply with values cached in hci_conn */
5624 rp.rssi = conn->rssi;
5625 rp.tx_power = conn->tx_power;
Andrzej Kaczmarekeed5daf2014-05-14 13:43:06 +02005626 rp.max_tx_power = conn->max_tx_power;
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005627
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005628 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO,
5629 MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
Andrzej Kaczmarekdd983802014-05-14 13:43:03 +02005630 }
5631
5632unlock:
5633 hci_dev_unlock(hdev);
5634 return err;
5635}
5636
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005637static int clock_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
Johan Hedberg69487372014-12-05 13:36:07 +02005638{
5639 struct hci_conn *conn = cmd->user_data;
5640 struct mgmt_rp_get_clock_info rp;
5641 struct hci_dev *hdev;
Johan Hedberg9df74652014-12-19 22:26:03 +02005642 int err;
Johan Hedberg69487372014-12-05 13:36:07 +02005643
5644 memset(&rp, 0, sizeof(rp));
5645 memcpy(&rp.addr, &cmd->param, sizeof(rp.addr));
5646
5647 if (status)
5648 goto complete;
5649
5650 hdev = hci_dev_get(cmd->index);
5651 if (hdev) {
5652 rp.local_clock = cpu_to_le32(hdev->clock);
5653 hci_dev_put(hdev);
5654 }
5655
5656 if (conn) {
5657 rp.piconet_clock = cpu_to_le32(conn->clock);
5658 rp.accuracy = cpu_to_le16(conn->clock_accuracy);
5659 }
5660
5661complete:
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005662 err = mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
5663 sizeof(rp));
Johan Hedberg69487372014-12-05 13:36:07 +02005664
5665 if (conn) {
5666 hci_conn_drop(conn);
5667 hci_conn_put(conn);
5668 }
Johan Hedberg9df74652014-12-19 22:26:03 +02005669
5670 return err;
Johan Hedberg69487372014-12-05 13:36:07 +02005671}
5672
Marcel Holtmann1904a852015-01-11 13:50:44 -08005673static void get_clock_info_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg95868422014-06-28 17:54:07 +03005674{
Johan Hedberg95868422014-06-28 17:54:07 +03005675 struct hci_cp_read_clock *hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005676 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005677 struct hci_conn *conn;
5678
5679 BT_DBG("%s status %u", hdev->name, status);
5680
5681 hci_dev_lock(hdev);
5682
5683 hci_cp = hci_sent_cmd_data(hdev, HCI_OP_READ_CLOCK);
5684 if (!hci_cp)
5685 goto unlock;
5686
5687 if (hci_cp->which) {
5688 u16 handle = __le16_to_cpu(hci_cp->handle);
5689 conn = hci_conn_hash_lookup_handle(hdev, handle);
5690 } else {
5691 conn = NULL;
5692 }
5693
5694 cmd = mgmt_pending_find_data(MGMT_OP_GET_CLOCK_INFO, hdev, conn);
5695 if (!cmd)
5696 goto unlock;
5697
Johan Hedberg69487372014-12-05 13:36:07 +02005698 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberg95868422014-06-28 17:54:07 +03005699 mgmt_pending_remove(cmd);
Johan Hedberg95868422014-06-28 17:54:07 +03005700
5701unlock:
5702 hci_dev_unlock(hdev);
5703}
5704
5705static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
5706 u16 len)
5707{
5708 struct mgmt_cp_get_clock_info *cp = data;
5709 struct mgmt_rp_get_clock_info rp;
5710 struct hci_cp_read_clock hci_cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005711 struct mgmt_pending_cmd *cmd;
Johan Hedberg95868422014-06-28 17:54:07 +03005712 struct hci_request req;
5713 struct hci_conn *conn;
5714 int err;
5715
5716 BT_DBG("%s", hdev->name);
5717
5718 memset(&rp, 0, sizeof(rp));
5719 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5720 rp.addr.type = cp->addr.type;
5721
5722 if (cp->addr.type != BDADDR_BREDR)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005723 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5724 MGMT_STATUS_INVALID_PARAMS,
5725 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005726
5727 hci_dev_lock(hdev);
5728
5729 if (!hdev_is_powered(hdev)) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005730 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CLOCK_INFO,
5731 MGMT_STATUS_NOT_POWERED, &rp,
5732 sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005733 goto unlock;
5734 }
5735
5736 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
5737 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
5738 &cp->addr.bdaddr);
5739 if (!conn || conn->state != BT_CONNECTED) {
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005740 err = mgmt_cmd_complete(sk, hdev->id,
5741 MGMT_OP_GET_CLOCK_INFO,
5742 MGMT_STATUS_NOT_CONNECTED,
5743 &rp, sizeof(rp));
Johan Hedberg95868422014-06-28 17:54:07 +03005744 goto unlock;
5745 }
5746 } else {
5747 conn = NULL;
5748 }
5749
5750 cmd = mgmt_pending_add(sk, MGMT_OP_GET_CLOCK_INFO, hdev, data, len);
5751 if (!cmd) {
5752 err = -ENOMEM;
5753 goto unlock;
5754 }
5755
Johan Hedberg69487372014-12-05 13:36:07 +02005756 cmd->cmd_complete = clock_info_cmd_complete;
5757
Johan Hedberg95868422014-06-28 17:54:07 +03005758 hci_req_init(&req, hdev);
5759
5760 memset(&hci_cp, 0, sizeof(hci_cp));
5761 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5762
5763 if (conn) {
5764 hci_conn_hold(conn);
Johan Hedbergf8aaf9b2014-08-17 23:28:57 +03005765 cmd->user_data = hci_conn_get(conn);
Johan Hedberg95868422014-06-28 17:54:07 +03005766
5767 hci_cp.handle = cpu_to_le16(conn->handle);
5768 hci_cp.which = 0x01; /* Piconet clock */
5769 hci_req_add(&req, HCI_OP_READ_CLOCK, sizeof(hci_cp), &hci_cp);
5770 }
5771
5772 err = hci_req_run(&req, get_clock_info_complete);
5773 if (err < 0)
5774 mgmt_pending_remove(cmd);
5775
5776unlock:
5777 hci_dev_unlock(hdev);
5778 return err;
5779}
5780
Johan Hedberg5a154e62014-12-19 22:26:02 +02005781static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
5782{
5783 struct hci_conn *conn;
5784
5785 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
5786 if (!conn)
5787 return false;
5788
5789 if (conn->dst_type != type)
5790 return false;
5791
5792 if (conn->state != BT_CONNECTED)
5793 return false;
5794
5795 return true;
5796}
5797
5798/* This function requires the caller holds hdev->lock */
5799static int hci_conn_params_set(struct hci_request *req, bdaddr_t *addr,
5800 u8 addr_type, u8 auto_connect)
5801{
5802 struct hci_dev *hdev = req->hdev;
5803 struct hci_conn_params *params;
5804
5805 params = hci_conn_params_add(hdev, addr, addr_type);
5806 if (!params)
5807 return -EIO;
5808
5809 if (params->auto_connect == auto_connect)
5810 return 0;
5811
5812 list_del_init(&params->action);
5813
5814 switch (auto_connect) {
5815 case HCI_AUTO_CONN_DISABLED:
5816 case HCI_AUTO_CONN_LINK_LOSS:
5817 __hci_update_background_scan(req);
5818 break;
5819 case HCI_AUTO_CONN_REPORT:
5820 list_add(&params->action, &hdev->pend_le_reports);
5821 __hci_update_background_scan(req);
5822 break;
5823 case HCI_AUTO_CONN_DIRECT:
5824 case HCI_AUTO_CONN_ALWAYS:
5825 if (!is_connected(hdev, addr, addr_type)) {
5826 list_add(&params->action, &hdev->pend_le_conns);
5827 __hci_update_background_scan(req);
5828 }
5829 break;
5830 }
5831
5832 params->auto_connect = auto_connect;
5833
5834 BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type,
5835 auto_connect);
5836
5837 return 0;
5838}
5839
Marcel Holtmann8afef092014-06-29 22:28:34 +02005840static void device_added(struct sock *sk, struct hci_dev *hdev,
5841 bdaddr_t *bdaddr, u8 type, u8 action)
5842{
5843 struct mgmt_ev_device_added ev;
5844
5845 bacpy(&ev.addr.bdaddr, bdaddr);
5846 ev.addr.type = type;
5847 ev.action = action;
5848
5849 mgmt_event(MGMT_EV_DEVICE_ADDED, hdev, &ev, sizeof(ev), sk);
5850}
5851
Marcel Holtmann1904a852015-01-11 13:50:44 -08005852static void add_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg5a154e62014-12-19 22:26:02 +02005853{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005854 struct mgmt_pending_cmd *cmd;
Johan Hedberg5a154e62014-12-19 22:26:02 +02005855
5856 BT_DBG("status 0x%02x", status);
5857
5858 hci_dev_lock(hdev);
5859
5860 cmd = mgmt_pending_find(MGMT_OP_ADD_DEVICE, hdev);
5861 if (!cmd)
5862 goto unlock;
5863
5864 cmd->cmd_complete(cmd, mgmt_status(status));
5865 mgmt_pending_remove(cmd);
5866
5867unlock:
5868 hci_dev_unlock(hdev);
5869}
5870
Marcel Holtmann2faade52014-06-29 19:44:03 +02005871static int add_device(struct sock *sk, struct hci_dev *hdev,
5872 void *data, u16 len)
5873{
5874 struct mgmt_cp_add_device *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005875 struct mgmt_pending_cmd *cmd;
Johan Hedberg5a154e62014-12-19 22:26:02 +02005876 struct hci_request req;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005877 u8 auto_conn, addr_type;
5878 int err;
5879
5880 BT_DBG("%s", hdev->name);
5881
Johan Hedberg66593582014-07-09 12:59:14 +03005882 if (!bdaddr_type_is_valid(cp->addr.type) ||
Marcel Holtmann2faade52014-06-29 19:44:03 +02005883 !bacmp(&cp->addr.bdaddr, BDADDR_ANY))
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005884 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5885 MGMT_STATUS_INVALID_PARAMS,
5886 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005887
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005888 if (cp->action != 0x00 && cp->action != 0x01 && cp->action != 0x02)
Johan Hedberg2a1afb52015-03-06 21:08:54 +02005889 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
5890 MGMT_STATUS_INVALID_PARAMS,
5891 &cp->addr, sizeof(cp->addr));
Marcel Holtmann2faade52014-06-29 19:44:03 +02005892
Johan Hedberg5a154e62014-12-19 22:26:02 +02005893 hci_req_init(&req, hdev);
5894
Marcel Holtmann2faade52014-06-29 19:44:03 +02005895 hci_dev_lock(hdev);
5896
Johan Hedberg5a154e62014-12-19 22:26:02 +02005897 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_DEVICE, hdev, data, len);
5898 if (!cmd) {
5899 err = -ENOMEM;
5900 goto unlock;
5901 }
5902
5903 cmd->cmd_complete = addr_cmd_complete;
5904
Johan Hedberg66593582014-07-09 12:59:14 +03005905 if (cp->addr.type == BDADDR_BREDR) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005906 /* Only incoming connections action is supported for now */
Johan Hedberg66593582014-07-09 12:59:14 +03005907 if (cp->action != 0x01) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005908 err = cmd->cmd_complete(cmd,
5909 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005910 mgmt_pending_remove(cmd);
Johan Hedberg66593582014-07-09 12:59:14 +03005911 goto unlock;
5912 }
5913
5914 err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
5915 cp->addr.type);
5916 if (err)
5917 goto unlock;
Johan Hedberga3974072014-07-09 12:59:15 +03005918
Johan Hedberg5a154e62014-12-19 22:26:02 +02005919 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03005920
Johan Hedberg66593582014-07-09 12:59:14 +03005921 goto added;
5922 }
5923
Marcel Holtmann2faade52014-06-29 19:44:03 +02005924 if (cp->addr.type == BDADDR_LE_PUBLIC)
5925 addr_type = ADDR_LE_DEV_PUBLIC;
5926 else
5927 addr_type = ADDR_LE_DEV_RANDOM;
5928
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005929 if (cp->action == 0x02)
Marcel Holtmann2faade52014-06-29 19:44:03 +02005930 auto_conn = HCI_AUTO_CONN_ALWAYS;
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02005931 else if (cp->action == 0x01)
5932 auto_conn = HCI_AUTO_CONN_DIRECT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005933 else
Johan Hedberga3451d22014-07-02 17:37:27 +03005934 auto_conn = HCI_AUTO_CONN_REPORT;
Marcel Holtmann2faade52014-06-29 19:44:03 +02005935
Marcel Holtmannbf5b3c82014-06-30 12:34:39 +02005936 /* If the connection parameters don't exist for this device,
5937 * they will be created and configured with defaults.
5938 */
Johan Hedberg5a154e62014-12-19 22:26:02 +02005939 if (hci_conn_params_set(&req, &cp->addr.bdaddr, addr_type,
Marcel Holtmannd06b50c2014-07-01 12:11:06 +02005940 auto_conn) < 0) {
Johan Hedberg9df74652014-12-19 22:26:03 +02005941 err = cmd->cmd_complete(cmd, MGMT_STATUS_FAILED);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005942 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02005943 goto unlock;
5944 }
5945
Johan Hedberg66593582014-07-09 12:59:14 +03005946added:
Marcel Holtmann8afef092014-06-29 22:28:34 +02005947 device_added(sk, hdev, &cp->addr.bdaddr, cp->addr.type, cp->action);
5948
Johan Hedberg5a154e62014-12-19 22:26:02 +02005949 err = hci_req_run(&req, add_device_complete);
5950 if (err < 0) {
5951 /* ENODATA means no HCI commands were needed (e.g. if
5952 * the adapter is powered off).
5953 */
Johan Hedberg9df74652014-12-19 22:26:03 +02005954 if (err == -ENODATA)
5955 err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
Johan Hedberg5a154e62014-12-19 22:26:02 +02005956 mgmt_pending_remove(cmd);
5957 }
Marcel Holtmann2faade52014-06-29 19:44:03 +02005958
5959unlock:
5960 hci_dev_unlock(hdev);
5961 return err;
5962}
5963
Marcel Holtmann8afef092014-06-29 22:28:34 +02005964static void device_removed(struct sock *sk, struct hci_dev *hdev,
5965 bdaddr_t *bdaddr, u8 type)
5966{
5967 struct mgmt_ev_device_removed ev;
5968
5969 bacpy(&ev.addr.bdaddr, bdaddr);
5970 ev.addr.type = type;
5971
5972 mgmt_event(MGMT_EV_DEVICE_REMOVED, hdev, &ev, sizeof(ev), sk);
5973}
5974
Marcel Holtmann1904a852015-01-11 13:50:44 -08005975static void remove_device_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005976{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005977 struct mgmt_pending_cmd *cmd;
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005978
5979 BT_DBG("status 0x%02x", status);
5980
5981 hci_dev_lock(hdev);
5982
5983 cmd = mgmt_pending_find(MGMT_OP_REMOVE_DEVICE, hdev);
5984 if (!cmd)
5985 goto unlock;
5986
5987 cmd->cmd_complete(cmd, mgmt_status(status));
5988 mgmt_pending_remove(cmd);
5989
5990unlock:
5991 hci_dev_unlock(hdev);
5992}
5993
Marcel Holtmann2faade52014-06-29 19:44:03 +02005994static int remove_device(struct sock *sk, struct hci_dev *hdev,
5995 void *data, u16 len)
5996{
5997 struct mgmt_cp_remove_device *cp = data;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02005998 struct mgmt_pending_cmd *cmd;
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02005999 struct hci_request req;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006000 int err;
6001
6002 BT_DBG("%s", hdev->name);
6003
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006004 hci_req_init(&req, hdev);
6005
Marcel Holtmann2faade52014-06-29 19:44:03 +02006006 hci_dev_lock(hdev);
6007
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006008 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_DEVICE, hdev, data, len);
6009 if (!cmd) {
6010 err = -ENOMEM;
6011 goto unlock;
6012 }
6013
6014 cmd->cmd_complete = addr_cmd_complete;
6015
Marcel Holtmann2faade52014-06-29 19:44:03 +02006016 if (bacmp(&cp->addr.bdaddr, BDADDR_ANY)) {
Johan Hedbergc71593d2014-07-02 17:37:28 +03006017 struct hci_conn_params *params;
Marcel Holtmann2faade52014-06-29 19:44:03 +02006018 u8 addr_type;
6019
Johan Hedberg66593582014-07-09 12:59:14 +03006020 if (!bdaddr_type_is_valid(cp->addr.type)) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006021 err = cmd->cmd_complete(cmd,
6022 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006023 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006024 goto unlock;
6025 }
6026
Johan Hedberg66593582014-07-09 12:59:14 +03006027 if (cp->addr.type == BDADDR_BREDR) {
6028 err = hci_bdaddr_list_del(&hdev->whitelist,
6029 &cp->addr.bdaddr,
6030 cp->addr.type);
6031 if (err) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006032 err = cmd->cmd_complete(cmd,
6033 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006034 mgmt_pending_remove(cmd);
Johan Hedberg66593582014-07-09 12:59:14 +03006035 goto unlock;
6036 }
6037
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006038 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03006039
Johan Hedberg66593582014-07-09 12:59:14 +03006040 device_removed(sk, hdev, &cp->addr.bdaddr,
6041 cp->addr.type);
6042 goto complete;
6043 }
6044
Marcel Holtmann2faade52014-06-29 19:44:03 +02006045 if (cp->addr.type == BDADDR_LE_PUBLIC)
6046 addr_type = ADDR_LE_DEV_PUBLIC;
6047 else
6048 addr_type = ADDR_LE_DEV_RANDOM;
6049
Johan Hedbergc71593d2014-07-02 17:37:28 +03006050 params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
6051 addr_type);
6052 if (!params) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006053 err = cmd->cmd_complete(cmd,
6054 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006055 mgmt_pending_remove(cmd);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006056 goto unlock;
6057 }
6058
6059 if (params->auto_connect == HCI_AUTO_CONN_DISABLED) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006060 err = cmd->cmd_complete(cmd,
6061 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006062 mgmt_pending_remove(cmd);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006063 goto unlock;
6064 }
6065
Johan Hedbergd1dbf122014-07-04 16:17:23 +03006066 list_del(&params->action);
Johan Hedbergc71593d2014-07-02 17:37:28 +03006067 list_del(&params->list);
6068 kfree(params);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006069 __hci_update_background_scan(&req);
Marcel Holtmann8afef092014-06-29 22:28:34 +02006070
6071 device_removed(sk, hdev, &cp->addr.bdaddr, cp->addr.type);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006072 } else {
Johan Hedberg19de0822014-07-06 13:06:51 +03006073 struct hci_conn_params *p, *tmp;
Johan Hedberg66593582014-07-09 12:59:14 +03006074 struct bdaddr_list *b, *btmp;
Johan Hedberg19de0822014-07-06 13:06:51 +03006075
Marcel Holtmann2faade52014-06-29 19:44:03 +02006076 if (cp->addr.type) {
Johan Hedberg9df74652014-12-19 22:26:03 +02006077 err = cmd->cmd_complete(cmd,
6078 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006079 mgmt_pending_remove(cmd);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006080 goto unlock;
6081 }
6082
Johan Hedberg66593582014-07-09 12:59:14 +03006083 list_for_each_entry_safe(b, btmp, &hdev->whitelist, list) {
6084 device_removed(sk, hdev, &b->bdaddr, b->bdaddr_type);
6085 list_del(&b->list);
6086 kfree(b);
6087 }
6088
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006089 __hci_update_page_scan(&req);
Johan Hedberga3974072014-07-09 12:59:15 +03006090
Johan Hedberg19de0822014-07-06 13:06:51 +03006091 list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
6092 if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
6093 continue;
6094 device_removed(sk, hdev, &p->addr, p->addr_type);
6095 list_del(&p->action);
6096 list_del(&p->list);
6097 kfree(p);
6098 }
6099
6100 BT_DBG("All LE connection parameters were removed");
6101
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006102 __hci_update_background_scan(&req);
Marcel Holtmann2faade52014-06-29 19:44:03 +02006103 }
6104
Johan Hedberg66593582014-07-09 12:59:14 +03006105complete:
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006106 err = hci_req_run(&req, remove_device_complete);
6107 if (err < 0) {
6108 /* ENODATA means no HCI commands were needed (e.g. if
6109 * the adapter is powered off).
6110 */
Johan Hedberg9df74652014-12-19 22:26:03 +02006111 if (err == -ENODATA)
6112 err = cmd->cmd_complete(cmd, MGMT_STATUS_SUCCESS);
Johan Hedberg51ef3eb2014-12-19 22:26:01 +02006113 mgmt_pending_remove(cmd);
6114 }
Marcel Holtmann2faade52014-06-29 19:44:03 +02006115
6116unlock:
6117 hci_dev_unlock(hdev);
6118 return err;
6119}
6120
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006121static int load_conn_param(struct sock *sk, struct hci_dev *hdev, void *data,
6122 u16 len)
6123{
6124 struct mgmt_cp_load_conn_param *cp = data;
Johan Hedbergba1d6932014-07-03 13:52:27 +03006125 const u16 max_param_count = ((U16_MAX - sizeof(*cp)) /
6126 sizeof(struct mgmt_conn_param));
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006127 u16 param_count, expected_len;
6128 int i;
6129
6130 if (!lmp_le_capable(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006131 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6132 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006133
6134 param_count = __le16_to_cpu(cp->param_count);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006135 if (param_count > max_param_count) {
6136 BT_ERR("load_conn_param: too big param_count value %u",
6137 param_count);
Johan Hedberga69e8372015-03-06 21:08:53 +02006138 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6139 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergba1d6932014-07-03 13:52:27 +03006140 }
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006141
6142 expected_len = sizeof(*cp) + param_count *
6143 sizeof(struct mgmt_conn_param);
6144 if (expected_len != len) {
6145 BT_ERR("load_conn_param: expected %u bytes, got %u bytes",
6146 expected_len, len);
Johan Hedberga69e8372015-03-06 21:08:53 +02006147 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM,
6148 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006149 }
6150
6151 BT_DBG("%s param_count %u", hdev->name, param_count);
6152
6153 hci_dev_lock(hdev);
6154
6155 hci_conn_params_clear_disabled(hdev);
6156
6157 for (i = 0; i < param_count; i++) {
6158 struct mgmt_conn_param *param = &cp->params[i];
6159 struct hci_conn_params *hci_param;
6160 u16 min, max, latency, timeout;
6161 u8 addr_type;
6162
6163 BT_DBG("Adding %pMR (type %u)", &param->addr.bdaddr,
6164 param->addr.type);
6165
6166 if (param->addr.type == BDADDR_LE_PUBLIC) {
6167 addr_type = ADDR_LE_DEV_PUBLIC;
6168 } else if (param->addr.type == BDADDR_LE_RANDOM) {
6169 addr_type = ADDR_LE_DEV_RANDOM;
6170 } else {
6171 BT_ERR("Ignoring invalid connection parameters");
6172 continue;
6173 }
6174
6175 min = le16_to_cpu(param->min_interval);
6176 max = le16_to_cpu(param->max_interval);
6177 latency = le16_to_cpu(param->latency);
6178 timeout = le16_to_cpu(param->timeout);
6179
6180 BT_DBG("min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
6181 min, max, latency, timeout);
6182
6183 if (hci_check_conn_params(min, max, latency, timeout) < 0) {
6184 BT_ERR("Ignoring invalid connection parameters");
6185 continue;
6186 }
6187
6188 hci_param = hci_conn_params_add(hdev, &param->addr.bdaddr,
6189 addr_type);
6190 if (!hci_param) {
6191 BT_ERR("Failed to add connection parameters");
6192 continue;
6193 }
6194
6195 hci_param->conn_min_interval = min;
6196 hci_param->conn_max_interval = max;
6197 hci_param->conn_latency = latency;
6198 hci_param->supervision_timeout = timeout;
6199 }
6200
6201 hci_dev_unlock(hdev);
6202
Johan Hedberg2a1afb52015-03-06 21:08:54 +02006203 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_LOAD_CONN_PARAM, 0,
6204 NULL, 0);
Johan Hedberga26f3dc2014-07-02 17:37:29 +03006205}
6206
Marcel Holtmanndbece372014-07-04 18:11:55 +02006207static int set_external_config(struct sock *sk, struct hci_dev *hdev,
6208 void *data, u16 len)
6209{
6210 struct mgmt_cp_set_external_config *cp = data;
6211 bool changed;
6212 int err;
6213
6214 BT_DBG("%s", hdev->name);
6215
6216 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006217 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6218 MGMT_STATUS_REJECTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006219
6220 if (cp->config != 0x00 && cp->config != 0x01)
Johan Hedberga69e8372015-03-06 21:08:53 +02006221 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6222 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006223
6224 if (!test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks))
Johan Hedberga69e8372015-03-06 21:08:53 +02006225 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_EXTERNAL_CONFIG,
6226 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006227
6228 hci_dev_lock(hdev);
6229
6230 if (cp->config)
Marcel Holtmann238be782015-03-13 02:11:06 -07006231 changed = !hci_dev_test_and_set_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006232 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07006233 changed = hci_dev_test_and_clear_flag(hdev, HCI_EXT_CONFIGURED);
Marcel Holtmanndbece372014-07-04 18:11:55 +02006234
6235 err = send_options_rsp(sk, MGMT_OP_SET_EXTERNAL_CONFIG, hdev);
6236 if (err < 0)
6237 goto unlock;
6238
6239 if (!changed)
6240 goto unlock;
6241
Marcel Holtmannf4537c02014-07-04 19:06:23 +02006242 err = new_options(hdev, sk);
6243
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006244 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) == is_configured(hdev)) {
Marcel Holtmanndbece372014-07-04 18:11:55 +02006245 mgmt_index_removed(hdev);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006246
Marcel Holtmann516018a2015-03-13 02:11:04 -07006247 if (hci_dev_test_and_change_flag(hdev, HCI_UNCONFIGURED)) {
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006248 hci_dev_set_flag(hdev, HCI_CONFIG);
6249 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006250
6251 queue_work(hdev->req_workqueue, &hdev->power_on);
6252 } else {
Marcel Holtmann5ea234d2014-07-06 12:11:16 +02006253 set_bit(HCI_RAW, &hdev->flags);
Marcel Holtmannd603b76b2014-07-06 12:11:14 +02006254 mgmt_index_added(hdev);
6255 }
Marcel Holtmanndbece372014-07-04 18:11:55 +02006256 }
6257
6258unlock:
6259 hci_dev_unlock(hdev);
6260 return err;
6261}
6262
Marcel Holtmann9713c172014-07-06 12:11:15 +02006263static int set_public_address(struct sock *sk, struct hci_dev *hdev,
6264 void *data, u16 len)
6265{
6266 struct mgmt_cp_set_public_address *cp = data;
6267 bool changed;
6268 int err;
6269
6270 BT_DBG("%s", hdev->name);
6271
6272 if (hdev_is_powered(hdev))
Johan Hedberga69e8372015-03-06 21:08:53 +02006273 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6274 MGMT_STATUS_REJECTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006275
6276 if (!bacmp(&cp->bdaddr, BDADDR_ANY))
Johan Hedberga69e8372015-03-06 21:08:53 +02006277 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6278 MGMT_STATUS_INVALID_PARAMS);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006279
6280 if (!hdev->set_bdaddr)
Johan Hedberga69e8372015-03-06 21:08:53 +02006281 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_PUBLIC_ADDRESS,
6282 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006283
6284 hci_dev_lock(hdev);
6285
6286 changed = !!bacmp(&hdev->public_addr, &cp->bdaddr);
6287 bacpy(&hdev->public_addr, &cp->bdaddr);
6288
6289 err = send_options_rsp(sk, MGMT_OP_SET_PUBLIC_ADDRESS, hdev);
6290 if (err < 0)
6291 goto unlock;
6292
6293 if (!changed)
6294 goto unlock;
6295
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006296 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED))
Marcel Holtmann9713c172014-07-06 12:11:15 +02006297 err = new_options(hdev, sk);
6298
6299 if (is_configured(hdev)) {
6300 mgmt_index_removed(hdev);
6301
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006302 hci_dev_clear_flag(hdev, HCI_UNCONFIGURED);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006303
Marcel Holtmanna1536da2015-03-13 02:11:01 -07006304 hci_dev_set_flag(hdev, HCI_CONFIG);
6305 hci_dev_set_flag(hdev, HCI_AUTO_OFF);
Marcel Holtmann9713c172014-07-06 12:11:15 +02006306
6307 queue_work(hdev->req_workqueue, &hdev->power_on);
6308 }
6309
6310unlock:
6311 hci_dev_unlock(hdev);
6312 return err;
6313}
6314
Marcel Holtmannbea41602015-03-14 22:43:17 -07006315static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
6316 u8 data_len)
6317{
6318 eir[eir_len++] = sizeof(type) + data_len;
6319 eir[eir_len++] = type;
6320 memcpy(&eir[eir_len], data, data_len);
6321 eir_len += data_len;
6322
6323 return eir_len;
6324}
6325
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006326static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev,
6327 void *data, u16 data_len)
6328{
6329 struct mgmt_cp_read_local_oob_ext_data *cp = data;
6330 struct mgmt_rp_read_local_oob_ext_data *rp;
6331 size_t rp_len;
6332 u16 eir_len;
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006333 u8 status, flags, role, addr[7], hash[16], rand[16];
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006334 int err;
6335
6336 BT_DBG("%s", hdev->name);
6337
6338 if (!hdev_is_powered(hdev))
6339 return mgmt_cmd_complete(sk, hdev->id,
6340 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6341 MGMT_STATUS_NOT_POWERED,
6342 &cp->type, sizeof(cp->type));
6343
6344 switch (cp->type) {
6345 case BIT(BDADDR_BREDR):
6346 status = mgmt_bredr_support(hdev);
6347 if (status)
6348 return mgmt_cmd_complete(sk, hdev->id,
6349 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6350 status, &cp->type,
6351 sizeof(cp->type));
6352 eir_len = 5;
6353 break;
6354 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
6355 status = mgmt_le_support(hdev);
6356 if (status)
6357 return mgmt_cmd_complete(sk, hdev->id,
6358 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6359 status, &cp->type,
6360 sizeof(cp->type));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006361 eir_len = 9 + 3 + 18 + 18 + 3;
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006362 break;
6363 default:
6364 return mgmt_cmd_complete(sk, hdev->id,
6365 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6366 MGMT_STATUS_INVALID_PARAMS,
6367 &cp->type, sizeof(cp->type));
6368 }
6369
6370 hci_dev_lock(hdev);
6371
6372 rp_len = sizeof(*rp) + eir_len;
6373 rp = kmalloc(rp_len, GFP_ATOMIC);
6374 if (!rp) {
6375 hci_dev_unlock(hdev);
6376 return -ENOMEM;
6377 }
6378
6379 eir_len = 0;
6380 switch (cp->type) {
6381 case BIT(BDADDR_BREDR):
6382 eir_len = eir_append_data(rp->eir, eir_len, EIR_CLASS_OF_DEV,
6383 hdev->dev_class, 3);
6384 break;
6385 case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)):
Marcel Holtmann5082a592015-03-16 12:39:00 -07006386 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) &&
6387 smp_generate_oob(hdev, hash, rand) < 0) {
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006388 hci_dev_unlock(hdev);
6389 err = mgmt_cmd_complete(sk, hdev->id,
Marcel Holtmann5082a592015-03-16 12:39:00 -07006390 MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
6391 MGMT_STATUS_FAILED,
6392 &cp->type, sizeof(cp->type));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006393 goto done;
6394 }
6395
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006396 if (hci_dev_test_flag(hdev, HCI_PRIVACY)) {
6397 memcpy(addr, &hdev->rpa, 6);
6398 addr[6] = 0x01;
6399 } else if (hci_dev_test_flag(hdev, HCI_FORCE_STATIC_ADDR) ||
6400 !bacmp(&hdev->bdaddr, BDADDR_ANY) ||
6401 (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED) &&
6402 bacmp(&hdev->static_addr, BDADDR_ANY))) {
6403 memcpy(addr, &hdev->static_addr, 6);
6404 addr[6] = 0x01;
6405 } else {
6406 memcpy(addr, &hdev->bdaddr, 6);
6407 addr[6] = 0x00;
6408 }
6409
6410 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_BDADDR,
6411 addr, sizeof(addr));
6412
6413 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
6414 role = 0x02;
6415 else
6416 role = 0x01;
6417
6418 eir_len = eir_append_data(rp->eir, eir_len, EIR_LE_ROLE,
6419 &role, sizeof(role));
6420
Marcel Holtmann5082a592015-03-16 12:39:00 -07006421 if (hci_dev_test_flag(hdev, HCI_SC_ENABLED)) {
6422 eir_len = eir_append_data(rp->eir, eir_len,
6423 EIR_LE_SC_CONFIRM,
6424 hash, sizeof(hash));
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006425
Marcel Holtmann5082a592015-03-16 12:39:00 -07006426 eir_len = eir_append_data(rp->eir, eir_len,
6427 EIR_LE_SC_RANDOM,
6428 rand, sizeof(rand));
6429 }
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006430
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006431 flags = get_adv_discov_flags(hdev);
6432
6433 if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
6434 flags |= LE_AD_NO_BREDR;
6435
6436 eir_len = eir_append_data(rp->eir, eir_len, EIR_FLAGS,
6437 &flags, sizeof(flags));
6438 break;
6439 }
6440
6441 rp->type = cp->type;
6442 rp->eir_len = cpu_to_le16(eir_len);
6443
6444 hci_dev_unlock(hdev);
6445
Marcel Holtmann72000df2015-03-16 16:11:21 -07006446 hci_sock_set_flag(sk, HCI_MGMT_OOB_DATA_EVENTS);
6447
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006448 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_EXT_DATA,
Marcel Holtmann5425f982015-03-16 16:05:44 -07006449 MGMT_STATUS_SUCCESS, rp, sizeof(*rp) + eir_len);
Marcel Holtmann72000df2015-03-16 16:11:21 -07006450 if (err < 0)
6451 goto done;
6452
6453 err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev,
6454 rp, sizeof(*rp) + eir_len,
6455 HCI_MGMT_OOB_DATA_EVENTS, sk);
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006456
Marcel Holtmann0821a2c2015-03-16 01:10:23 -07006457done:
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006458 kfree(rp);
6459
6460 return err;
6461}
6462
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006463static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
6464 void *data, u16 data_len)
6465{
6466 struct mgmt_rp_read_adv_features *rp;
6467 size_t rp_len;
6468 int err;
6469
6470 BT_DBG("%s", hdev->name);
6471
6472 hci_dev_lock(hdev);
6473
6474 rp_len = sizeof(*rp);
6475 rp = kmalloc(rp_len, GFP_ATOMIC);
6476 if (!rp) {
6477 hci_dev_unlock(hdev);
6478 return -ENOMEM;
6479 }
6480
6481 rp->supported_flags = cpu_to_le32(0);
6482 rp->max_adv_data_len = 31;
6483 rp->max_scan_rsp_len = 31;
6484 rp->max_instances = 0;
6485 rp->num_instances = 0;
6486
6487 hci_dev_unlock(hdev);
6488
6489 err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES,
6490 MGMT_STATUS_SUCCESS, rp, rp_len);
6491
6492 kfree(rp);
6493
6494 return err;
6495}
6496
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006497static const struct hci_mgmt_handler mgmt_handlers[] = {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006498 { NULL }, /* 0x0000 (no command) */
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006499 { read_version, MGMT_READ_VERSION_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006500 HCI_MGMT_NO_HDEV |
6501 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006502 { read_commands, MGMT_READ_COMMANDS_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006503 HCI_MGMT_NO_HDEV |
6504 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006505 { read_index_list, MGMT_READ_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006506 HCI_MGMT_NO_HDEV |
6507 HCI_MGMT_UNTRUSTED },
6508 { read_controller_info, MGMT_READ_INFO_SIZE,
6509 HCI_MGMT_UNTRUSTED },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006510 { set_powered, MGMT_SETTING_SIZE },
6511 { set_discoverable, MGMT_SET_DISCOVERABLE_SIZE },
6512 { set_connectable, MGMT_SETTING_SIZE },
6513 { set_fast_connectable, MGMT_SETTING_SIZE },
6514 { set_bondable, MGMT_SETTING_SIZE },
6515 { set_link_security, MGMT_SETTING_SIZE },
6516 { set_ssp, MGMT_SETTING_SIZE },
6517 { set_hs, MGMT_SETTING_SIZE },
6518 { set_le, MGMT_SETTING_SIZE },
6519 { set_dev_class, MGMT_SET_DEV_CLASS_SIZE },
6520 { set_local_name, MGMT_SET_LOCAL_NAME_SIZE },
6521 { add_uuid, MGMT_ADD_UUID_SIZE },
6522 { remove_uuid, MGMT_REMOVE_UUID_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006523 { load_link_keys, MGMT_LOAD_LINK_KEYS_SIZE,
6524 HCI_MGMT_VAR_LEN },
6525 { load_long_term_keys, MGMT_LOAD_LONG_TERM_KEYS_SIZE,
6526 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006527 { disconnect, MGMT_DISCONNECT_SIZE },
6528 { get_connections, MGMT_GET_CONNECTIONS_SIZE },
6529 { pin_code_reply, MGMT_PIN_CODE_REPLY_SIZE },
6530 { pin_code_neg_reply, MGMT_PIN_CODE_NEG_REPLY_SIZE },
6531 { set_io_capability, MGMT_SET_IO_CAPABILITY_SIZE },
6532 { pair_device, MGMT_PAIR_DEVICE_SIZE },
6533 { cancel_pair_device, MGMT_CANCEL_PAIR_DEVICE_SIZE },
6534 { unpair_device, MGMT_UNPAIR_DEVICE_SIZE },
6535 { user_confirm_reply, MGMT_USER_CONFIRM_REPLY_SIZE },
6536 { user_confirm_neg_reply, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
6537 { user_passkey_reply, MGMT_USER_PASSKEY_REPLY_SIZE },
6538 { user_passkey_neg_reply, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006539 { read_local_oob_data, MGMT_READ_LOCAL_OOB_DATA_SIZE },
6540 { add_remote_oob_data, MGMT_ADD_REMOTE_OOB_DATA_SIZE,
6541 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006542 { remove_remote_oob_data, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
6543 { start_discovery, MGMT_START_DISCOVERY_SIZE },
6544 { stop_discovery, MGMT_STOP_DISCOVERY_SIZE },
6545 { confirm_name, MGMT_CONFIRM_NAME_SIZE },
6546 { block_device, MGMT_BLOCK_DEVICE_SIZE },
6547 { unblock_device, MGMT_UNBLOCK_DEVICE_SIZE },
6548 { set_device_id, MGMT_SET_DEVICE_ID_SIZE },
6549 { set_advertising, MGMT_SETTING_SIZE },
6550 { set_bredr, MGMT_SETTING_SIZE },
6551 { set_static_address, MGMT_SET_STATIC_ADDRESS_SIZE },
6552 { set_scan_params, MGMT_SET_SCAN_PARAMS_SIZE },
6553 { set_secure_conn, MGMT_SETTING_SIZE },
6554 { set_debug_keys, MGMT_SETTING_SIZE },
6555 { set_privacy, MGMT_SET_PRIVACY_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006556 { load_irks, MGMT_LOAD_IRKS_SIZE,
6557 HCI_MGMT_VAR_LEN },
Marcel Holtmann7aea86162015-03-14 19:28:02 -07006558 { get_conn_info, MGMT_GET_CONN_INFO_SIZE },
6559 { get_clock_info, MGMT_GET_CLOCK_INFO_SIZE },
6560 { add_device, MGMT_ADD_DEVICE_SIZE },
6561 { remove_device, MGMT_REMOVE_DEVICE_SIZE },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006562 { load_conn_param, MGMT_LOAD_CONN_PARAM_SIZE,
6563 HCI_MGMT_VAR_LEN },
6564 { read_unconf_index_list, MGMT_READ_UNCONF_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006565 HCI_MGMT_NO_HDEV |
6566 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006567 { read_config_info, MGMT_READ_CONFIG_INFO_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006568 HCI_MGMT_UNCONFIGURED |
6569 HCI_MGMT_UNTRUSTED },
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006570 { set_external_config, MGMT_SET_EXTERNAL_CONFIG_SIZE,
6571 HCI_MGMT_UNCONFIGURED },
6572 { set_public_address, MGMT_SET_PUBLIC_ADDRESS_SIZE,
6573 HCI_MGMT_UNCONFIGURED },
6574 { start_service_discovery, MGMT_START_SERVICE_DISCOVERY_SIZE,
6575 HCI_MGMT_VAR_LEN },
Marcel Holtmann4f0f1552015-03-14 22:43:19 -07006576 { read_local_oob_ext_data, MGMT_READ_LOCAL_OOB_EXT_DATA_SIZE },
Marcel Holtmann96f14742015-03-14 19:27:57 -07006577 { read_ext_index_list, MGMT_READ_EXT_INDEX_LIST_SIZE,
Marcel Holtmannc91041d2015-03-14 19:28:01 -07006578 HCI_MGMT_NO_HDEV |
6579 HCI_MGMT_UNTRUSTED },
Marcel Holtmannd3d53052015-03-14 20:53:25 -07006580 { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006581};
6582
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006583int mgmt_control(struct hci_mgmt_chan *chan, struct sock *sk,
6584 struct msghdr *msg, size_t msglen)
Johan Hedberg03811012010-12-08 00:21:06 +02006585{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03006586 void *buf;
6587 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02006588 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01006589 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006590 struct hci_dev *hdev = NULL;
Johan Hedberg6d785aa32015-03-06 21:08:51 +02006591 const struct hci_mgmt_handler *handler;
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006592 bool var_len, no_hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02006593 int err;
6594
6595 BT_DBG("got %zu bytes", msglen);
6596
6597 if (msglen < sizeof(*hdr))
6598 return -EINVAL;
6599
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03006600 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02006601 if (!buf)
6602 return -ENOMEM;
6603
Al Viro6ce8e9c2014-04-06 21:25:44 -04006604 if (memcpy_from_msg(buf, msg, msglen)) {
Johan Hedberg03811012010-12-08 00:21:06 +02006605 err = -EFAULT;
6606 goto done;
6607 }
6608
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03006609 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07006610 opcode = __le16_to_cpu(hdr->opcode);
6611 index = __le16_to_cpu(hdr->index);
6612 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02006613
6614 if (len != msglen - sizeof(*hdr)) {
6615 err = -EINVAL;
6616 goto done;
6617 }
6618
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006619 if (opcode >= chan->handler_count ||
6620 chan->handlers[opcode].func == NULL) {
6621 BT_DBG("Unknown op %u", opcode);
Johan Hedberga69e8372015-03-06 21:08:53 +02006622 err = mgmt_cmd_status(sk, index, opcode,
6623 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006624 goto done;
6625 }
6626
6627 handler = &chan->handlers[opcode];
6628
Marcel Holtmannc927a102015-03-14 19:28:03 -07006629 if (!hci_sock_test_flag(sk, HCI_SOCK_TRUSTED) &&
6630 !(handler->flags & HCI_MGMT_UNTRUSTED)) {
6631 err = mgmt_cmd_status(sk, index, opcode,
6632 MGMT_STATUS_PERMISSION_DENIED);
6633 goto done;
6634 }
6635
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006636 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006637 hdev = hci_dev_get(index);
6638 if (!hdev) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006639 err = mgmt_cmd_status(sk, index, opcode,
6640 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006641 goto done;
6642 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07006643
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006644 if (hci_dev_test_flag(hdev, HCI_SETUP) ||
6645 hci_dev_test_flag(hdev, HCI_CONFIG) ||
6646 hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006647 err = mgmt_cmd_status(sk, index, opcode,
6648 MGMT_STATUS_INVALID_INDEX);
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07006649 goto done;
6650 }
Marcel Holtmann42a9bc142014-07-04 16:54:40 +02006651
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006652 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006653 !(handler->flags & HCI_MGMT_UNCONFIGURED)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006654 err = mgmt_cmd_status(sk, index, opcode,
6655 MGMT_STATUS_INVALID_INDEX);
Marcel Holtmann42a9bc142014-07-04 16:54:40 +02006656 goto done;
6657 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006658 }
6659
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006660 no_hdev = (handler->flags & HCI_MGMT_NO_HDEV);
6661 if (no_hdev != !hdev) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006662 err = mgmt_cmd_status(sk, index, opcode,
6663 MGMT_STATUS_INVALID_INDEX);
Marcel Holtmann73d1df22014-07-02 22:10:52 +02006664 goto done;
6665 }
6666
Johan Hedbergb9a245fb2015-03-06 21:08:52 +02006667 var_len = (handler->flags & HCI_MGMT_VAR_LEN);
6668 if ((var_len && len < handler->data_len) ||
6669 (!var_len && len != handler->data_len)) {
Johan Hedberga69e8372015-03-06 21:08:53 +02006670 err = mgmt_cmd_status(sk, index, opcode,
6671 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02006672 goto done;
6673 }
6674
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02006675 if (hdev)
6676 mgmt_init_hdev(sk, hdev);
6677
6678 cp = buf + sizeof(*hdr);
6679
Johan Hedbergbe22b542012-03-01 22:24:41 +02006680 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02006681 if (err < 0)
6682 goto done;
6683
Johan Hedberg03811012010-12-08 00:21:06 +02006684 err = msglen;
6685
6686done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02006687 if (hdev)
6688 hci_dev_put(hdev);
6689
Johan Hedberg03811012010-12-08 00:21:06 +02006690 kfree(buf);
6691 return err;
6692}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006693
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006694void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006695{
Marcel Holtmannced85542015-03-14 19:27:56 -07006696 struct mgmt_ev_ext_index ev;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03006697
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006698 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6699 return;
6700
Marcel Holtmannf9207332015-03-14 19:27:55 -07006701 switch (hdev->dev_type) {
6702 case HCI_BREDR:
6703 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6704 mgmt_index_event(MGMT_EV_UNCONF_INDEX_ADDED, hdev,
6705 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006706 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006707 } else {
6708 mgmt_index_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0,
6709 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006710 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006711 }
6712 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006713 case HCI_AMP:
6714 ev.type = 0x02;
6715 break;
6716 default:
6717 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006718 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006719
6720 ev.bus = hdev->bus;
6721
6722 mgmt_index_event(MGMT_EV_EXT_INDEX_ADDED, hdev, &ev, sizeof(ev),
6723 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006724}
6725
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07006726void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02006727{
Marcel Holtmannced85542015-03-14 19:27:56 -07006728 struct mgmt_ev_ext_index ev;
Johan Hedberg5f159032012-03-02 03:13:19 +02006729 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006730
Marcel Holtmann0602a8a2014-07-02 21:30:54 +02006731 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
6732 return;
6733
Marcel Holtmannf9207332015-03-14 19:27:55 -07006734 switch (hdev->dev_type) {
6735 case HCI_BREDR:
6736 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02006737
Marcel Holtmannf9207332015-03-14 19:27:55 -07006738 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
6739 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev,
6740 NULL, 0, HCI_MGMT_UNCONF_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006741 ev.type = 0x01;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006742 } else {
6743 mgmt_index_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0,
6744 HCI_MGMT_INDEX_EVENTS);
Marcel Holtmannced85542015-03-14 19:27:56 -07006745 ev.type = 0x00;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006746 }
6747 break;
Marcel Holtmannced85542015-03-14 19:27:56 -07006748 case HCI_AMP:
6749 ev.type = 0x02;
6750 break;
6751 default:
6752 return;
Marcel Holtmannf9207332015-03-14 19:27:55 -07006753 }
Marcel Holtmannced85542015-03-14 19:27:56 -07006754
6755 ev.bus = hdev->bus;
6756
6757 mgmt_index_event(MGMT_EV_EXT_INDEX_REMOVED, hdev, &ev, sizeof(ev),
6758 HCI_MGMT_EXT_INDEX_EVENTS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006759}
6760
Andre Guedes6046dc32014-02-26 20:21:51 -03006761/* This function requires the caller holds hdev->lock */
Johan Hedberg2cf22212014-12-19 22:26:00 +02006762static void restart_le_actions(struct hci_request *req)
Andre Guedes6046dc32014-02-26 20:21:51 -03006763{
Johan Hedberg2cf22212014-12-19 22:26:00 +02006764 struct hci_dev *hdev = req->hdev;
Andre Guedes6046dc32014-02-26 20:21:51 -03006765 struct hci_conn_params *p;
6766
6767 list_for_each_entry(p, &hdev->le_conn_params, list) {
Johan Hedbergd7347f32014-07-04 12:37:23 +03006768 /* Needed for AUTO_OFF case where might not "really"
6769 * have been powered off.
6770 */
6771 list_del_init(&p->action);
6772
6773 switch (p->auto_connect) {
Marcel Holtmann4b9e7e72014-07-23 21:55:23 +02006774 case HCI_AUTO_CONN_DIRECT:
Johan Hedbergd7347f32014-07-04 12:37:23 +03006775 case HCI_AUTO_CONN_ALWAYS:
6776 list_add(&p->action, &hdev->pend_le_conns);
6777 break;
6778 case HCI_AUTO_CONN_REPORT:
6779 list_add(&p->action, &hdev->pend_le_reports);
6780 break;
6781 default:
6782 break;
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006783 }
Andre Guedes6046dc32014-02-26 20:21:51 -03006784 }
Marcel Holtmannc83ed192014-07-01 19:28:24 +02006785
Johan Hedberg2cf22212014-12-19 22:26:00 +02006786 __hci_update_background_scan(req);
Andre Guedes6046dc32014-02-26 20:21:51 -03006787}
6788
Marcel Holtmann1904a852015-01-11 13:50:44 -08006789static void powered_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Johan Hedberg229ab392013-03-15 17:06:53 -05006790{
6791 struct cmd_lookup match = { NULL, hdev };
6792
6793 BT_DBG("status 0x%02x", status);
6794
Marcel Holtmann162a3ba2015-01-14 15:43:11 -08006795 if (!status) {
6796 /* Register the available SMP channels (BR/EDR and LE) only
6797 * when successfully powering on the controller. This late
6798 * registration is required so that LE SMP can clearly
6799 * decide if the public address or static address is used.
6800 */
6801 smp_register(hdev);
6802 }
6803
Johan Hedberg229ab392013-03-15 17:06:53 -05006804 hci_dev_lock(hdev);
6805
6806 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
6807
6808 new_settings(hdev, match.sk);
6809
6810 hci_dev_unlock(hdev);
6811
6812 if (match.sk)
6813 sock_put(match.sk);
6814}
6815
Johan Hedberg70da6242013-03-15 17:06:51 -05006816static int powered_update_hci(struct hci_dev *hdev)
6817{
Johan Hedberg890ea892013-03-15 17:06:52 -05006818 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05006819 u8 link_sec;
6820
Johan Hedberg890ea892013-03-15 17:06:52 -05006821 hci_req_init(&req, hdev);
6822
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006823 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED) &&
Johan Hedberg70da6242013-03-15 17:06:51 -05006824 !lmp_host_ssp_capable(hdev)) {
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006825 u8 mode = 0x01;
Johan Hedberg70da6242013-03-15 17:06:51 -05006826
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006827 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
Johan Hedberg70da6242013-03-15 17:06:51 -05006828
Marcel Holtmann574ea3c2015-01-22 11:15:20 -08006829 if (bredr_sc_enabled(hdev) && !lmp_host_sc_capable(hdev)) {
6830 u8 support = 0x01;
6831
6832 hci_req_add(&req, HCI_OP_WRITE_SC_SUPPORT,
6833 sizeof(support), &support);
6834 }
Johan Hedbergec6f99b2014-12-12 13:30:11 +02006835 }
6836
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006837 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED) &&
Johan Hedbergc73eee92013-04-19 18:35:21 +03006838 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05006839 struct hci_cp_write_le_host_supported cp;
6840
Marcel Holtmann32226e42014-07-24 20:04:16 +02006841 cp.le = 0x01;
6842 cp.simul = 0x00;
Johan Hedberg70da6242013-03-15 17:06:51 -05006843
6844 /* Check first if we already have the right
6845 * host state (host features set)
6846 */
6847 if (cp.le != lmp_host_le_capable(hdev) ||
6848 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05006849 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
6850 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05006851 }
6852
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07006853 if (lmp_le_capable(hdev)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006854 /* Make sure the controller has a good default for
6855 * advertising data. This also applies to the case
6856 * where BR/EDR was toggled during the AUTO_OFF phase.
6857 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006858 if (hci_dev_test_flag(hdev, HCI_LE_ENABLED)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07006859 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07006860 update_scan_rsp_data(&req);
6861 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07006862
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006863 if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07006864 enable_advertising(&req);
Johan Hedberg2cf22212014-12-19 22:26:00 +02006865
6866 restart_le_actions(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03006867 }
6868
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006869 link_sec = hci_dev_test_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg70da6242013-03-15 17:06:51 -05006870 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05006871 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
6872 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05006873
6874 if (lmp_bredr_capable(hdev)) {
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006875 if (hci_dev_test_flag(hdev, HCI_FAST_CONNECTABLE))
Johan Hedberg406ef2a2015-03-10 20:14:27 +02006876 write_fast_connectable(&req, true);
6877 else
6878 write_fast_connectable(&req, false);
Johan Hedberg1d2dc5b2014-12-19 13:40:19 +02006879 __hci_update_page_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006880 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05006881 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05006882 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05006883 }
6884
Johan Hedberg229ab392013-03-15 17:06:53 -05006885 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05006886}
6887
Johan Hedberg744cf192011-11-08 20:40:14 +02006888int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02006889{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02006890 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg98459042014-12-12 11:15:21 +02006891 u8 status, zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006892 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006893
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006894 if (!hci_dev_test_flag(hdev, HCI_MGMT))
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006895 return 0;
6896
Johan Hedberg5e5282b2012-02-21 16:01:30 +02006897 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05006898 if (powered_update_hci(hdev) == 0)
6899 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02006900
Johan Hedberg229ab392013-03-15 17:06:53 -05006901 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
6902 &match);
6903 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02006904 }
6905
Johan Hedberg229ab392013-03-15 17:06:53 -05006906 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg98459042014-12-12 11:15:21 +02006907
6908 /* If the power off is because of hdev unregistration let
6909 * use the appropriate INVALID_INDEX status. Otherwise use
6910 * NOT_POWERED. We cover both scenarios here since later in
6911 * mgmt_index_removed() any hci_conn callbacks will have already
6912 * been triggered, potentially causing misleading DISCONNECTED
6913 * status responses.
6914 */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006915 if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
Johan Hedberg98459042014-12-12 11:15:21 +02006916 status = MGMT_STATUS_INVALID_INDEX;
6917 else
6918 status = MGMT_STATUS_NOT_POWERED;
6919
6920 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
Johan Hedberg229ab392013-03-15 17:06:53 -05006921
6922 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07006923 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6924 zero_cod, sizeof(zero_cod), NULL);
Johan Hedberg229ab392013-03-15 17:06:53 -05006925
6926new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02006927 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02006928
6929 if (match.sk)
6930 sock_put(match.sk);
6931
Johan Hedberg7bb895d2012-02-17 01:20:00 +02006932 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02006933}
Johan Hedberg73f22f62010-12-29 16:00:25 +02006934
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006935void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03006936{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02006937 struct mgmt_pending_cmd *cmd;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006938 u8 status;
6939
6940 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
6941 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07006942 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03006943
6944 if (err == -ERFKILL)
6945 status = MGMT_STATUS_RFKILLED;
6946 else
6947 status = MGMT_STATUS_FAILED;
6948
Johan Hedberga69e8372015-03-06 21:08:53 +02006949 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006950
6951 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03006952}
6953
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006954void mgmt_discoverable_timeout(struct hci_dev *hdev)
6955{
6956 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006957
6958 hci_dev_lock(hdev);
6959
6960 /* When discoverable timeout triggers, then just make sure
6961 * the limited discoverable flag is cleared. Even in the case
6962 * of a timeout triggered from general discoverable, it is
6963 * safe to unconditionally clear the flag.
6964 */
Marcel Holtmanna358dc12015-03-13 02:11:02 -07006965 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
6966 hci_dev_clear_flag(hdev, HCI_DISCOVERABLE);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006967
6968 hci_req_init(&req, hdev);
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07006969 if (hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) {
Johan Hedberg4b580612013-10-19 23:38:21 +03006970 u8 scan = SCAN_PAGE;
6971 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
6972 sizeof(scan), &scan);
6973 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006974 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03006975 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006976 hci_req_run(&req, NULL);
6977
6978 hdev->discov_timeout = 0;
6979
Johan Hedberg9a43e252013-10-20 19:00:07 +03006980 new_settings(hdev, NULL);
6981
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07006982 hci_dev_unlock(hdev);
6983}
6984
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006985void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
6986 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006987{
Johan Hedberg86742e12011-11-07 23:13:38 +02006988 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006989
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006990 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006991
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006992 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02006993 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03006994 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006995 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03006996 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03006997 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02006998
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07006999 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02007000}
Johan Hedbergf7520542011-01-20 12:34:39 +02007001
Johan Hedbergd7b25452014-05-23 13:19:53 +03007002static u8 mgmt_ltk_type(struct smp_ltk *ltk)
7003{
Johan Hedberg23fb8de2014-05-23 13:15:37 +03007004 switch (ltk->type) {
7005 case SMP_LTK:
7006 case SMP_LTK_SLAVE:
7007 if (ltk->authenticated)
7008 return MGMT_LTK_AUTHENTICATED;
7009 return MGMT_LTK_UNAUTHENTICATED;
7010 case SMP_LTK_P256:
7011 if (ltk->authenticated)
7012 return MGMT_LTK_P256_AUTH;
7013 return MGMT_LTK_P256_UNAUTH;
7014 case SMP_LTK_P256_DEBUG:
7015 return MGMT_LTK_P256_DEBUG;
7016 }
Johan Hedbergd7b25452014-05-23 13:19:53 +03007017
7018 return MGMT_LTK_UNAUTHENTICATED;
7019}
7020
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007021void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007022{
7023 struct mgmt_ev_new_long_term_key ev;
7024
7025 memset(&ev, 0, sizeof(ev));
7026
Marcel Holtmann5192d302014-02-19 17:11:58 -08007027 /* Devices using resolvable or non-resolvable random addresses
7028 * without providing an indentity resolving key don't require
7029 * to store long term keys. Their addresses will change the
7030 * next time around.
7031 *
7032 * Only when a remote device provides an identity address
7033 * make sure the long term key is stored. If the remote
7034 * identity is known, the long term keys are internally
7035 * mapped to the identity address. So allow static random
7036 * and public addresses here.
7037 */
Johan Hedbergba74b662014-02-19 14:57:45 +02007038 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7039 (key->bdaddr.b[5] & 0xc0) != 0xc0)
7040 ev.store_hint = 0x00;
7041 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007042 ev.store_hint = persistent;
Johan Hedbergba74b662014-02-19 14:57:45 +02007043
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007044 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007045 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Johan Hedbergd7b25452014-05-23 13:19:53 +03007046 ev.key.type = mgmt_ltk_type(key);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007047 ev.key.enc_size = key->enc_size;
7048 ev.key.ediv = key->ediv;
Marcel Holtmannfe39c7b2014-02-27 16:00:28 -08007049 ev.key.rand = key->rand;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007050
Johan Hedberg2ceba532014-06-16 19:25:16 +03007051 if (key->type == SMP_LTK)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007052 ev.key.master = 1;
7053
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007054 memcpy(ev.key.val, key->val, sizeof(key->val));
7055
Marcel Holtmann083368f2013-10-15 14:26:29 -07007056 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03007057}
7058
Johan Hedberg95fbac82014-02-19 15:18:31 +02007059void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk)
7060{
7061 struct mgmt_ev_new_irk ev;
7062
7063 memset(&ev, 0, sizeof(ev));
7064
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08007065 /* For identity resolving keys from devices that are already
7066 * using a public address or static random address, do not
7067 * ask for storing this key. The identity resolving key really
7068 * is only mandatory for devices using resovlable random
7069 * addresses.
7070 *
7071 * Storing all identity resolving keys has the downside that
7072 * they will be also loaded on next boot of they system. More
7073 * identity resolving keys, means more time during scanning is
7074 * needed to actually resolve these addresses.
7075 */
7076 if (bacmp(&irk->rpa, BDADDR_ANY))
7077 ev.store_hint = 0x01;
7078 else
7079 ev.store_hint = 0x00;
7080
Johan Hedberg95fbac82014-02-19 15:18:31 +02007081 bacpy(&ev.rpa, &irk->rpa);
7082 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
7083 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
7084 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
7085
7086 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
7087}
7088
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007089void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
7090 bool persistent)
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007091{
7092 struct mgmt_ev_new_csrk ev;
7093
7094 memset(&ev, 0, sizeof(ev));
7095
7096 /* Devices using resolvable or non-resolvable random addresses
7097 * without providing an indentity resolving key don't require
7098 * to store signature resolving keys. Their addresses will change
7099 * the next time around.
7100 *
7101 * Only when a remote device provides an identity address
7102 * make sure the signature resolving key is stored. So allow
7103 * static random and public addresses here.
7104 */
7105 if (csrk->bdaddr_type == ADDR_LE_DEV_RANDOM &&
7106 (csrk->bdaddr.b[5] & 0xc0) != 0xc0)
7107 ev.store_hint = 0x00;
7108 else
Marcel Holtmann53ac6ab2014-03-09 23:38:42 -07007109 ev.store_hint = persistent;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007110
7111 bacpy(&ev.key.addr.bdaddr, &csrk->bdaddr);
7112 ev.key.addr.type = link_to_bdaddr(LE_LINK, csrk->bdaddr_type);
Johan Hedberg4cd39282015-02-27 10:11:13 +02007113 ev.key.type = csrk->type;
Marcel Holtmann7ee4ea32014-03-09 12:19:17 -07007114 memcpy(ev.key.val, csrk->val, sizeof(csrk->val));
7115
7116 mgmt_event(MGMT_EV_NEW_CSRK, hdev, &ev, sizeof(ev), NULL);
7117}
7118
Andre Guedesffb5a8272014-07-01 18:10:11 -03007119void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedbergf4869e22014-07-02 17:37:32 +03007120 u8 bdaddr_type, u8 store_hint, u16 min_interval,
7121 u16 max_interval, u16 latency, u16 timeout)
Andre Guedesffb5a8272014-07-01 18:10:11 -03007122{
7123 struct mgmt_ev_new_conn_param ev;
7124
Johan Hedbergc103aea2014-07-02 17:37:34 +03007125 if (!hci_is_identity_address(bdaddr, bdaddr_type))
7126 return;
7127
Andre Guedesffb5a8272014-07-01 18:10:11 -03007128 memset(&ev, 0, sizeof(ev));
7129 bacpy(&ev.addr.bdaddr, bdaddr);
7130 ev.addr.type = link_to_bdaddr(LE_LINK, bdaddr_type);
Johan Hedbergf4869e22014-07-02 17:37:32 +03007131 ev.store_hint = store_hint;
Andre Guedesffb5a8272014-07-01 18:10:11 -03007132 ev.min_interval = cpu_to_le16(min_interval);
7133 ev.max_interval = cpu_to_le16(max_interval);
7134 ev.latency = cpu_to_le16(latency);
7135 ev.timeout = cpu_to_le16(timeout);
7136
7137 mgmt_event(MGMT_EV_NEW_CONN_PARAM, hdev, &ev, sizeof(ev), NULL);
7138}
7139
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007140void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
7141 u32 flags, u8 *name, u8 name_len)
Johan Hedbergf7520542011-01-20 12:34:39 +02007142{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007143 char buf[512];
7144 struct mgmt_ev_device_connected *ev = (void *) buf;
7145 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02007146
Alfonso Acosta48ec92f2014-10-07 08:44:10 +00007147 bacpy(&ev->addr.bdaddr, &conn->dst);
7148 ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02007149
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02007150 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02007151
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007152 /* We must ensure that the EIR Data fields are ordered and
7153 * unique. Keep it simple for now and avoid the problem by not
7154 * adding any BR/EDR data to the LE adv.
7155 */
7156 if (conn->le_adv_data_len > 0) {
7157 memcpy(&ev->eir[eir_len],
7158 conn->le_adv_data, conn->le_adv_data_len);
7159 eir_len = conn->le_adv_data_len;
7160 } else {
7161 if (name_len > 0)
7162 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
7163 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007164
Alfonso Acostaddbea5c2014-10-07 08:44:12 +00007165 if (memcmp(conn->dev_class, "\0\0\0", 3) != 0)
Alfonso Acostafd45ada2014-10-07 08:44:11 +00007166 eir_len = eir_append_data(ev->eir, eir_len,
7167 EIR_CLASS_OF_DEV,
7168 conn->dev_class, 3);
7169 }
Johan Hedbergb644ba32012-01-17 21:48:47 +02007170
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007171 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007172
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07007173 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
7174 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02007175}
7176
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007177static void disconnect_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007178{
Johan Hedberg8962ee72011-01-20 12:40:27 +02007179 struct sock **sk = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007180
Johan Hedbergf5818c22014-12-05 13:36:02 +02007181 cmd->cmd_complete(cmd, 0);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007182
7183 *sk = cmd->sk;
7184 sock_hold(*sk);
7185
Johan Hedberga664b5b2011-02-19 12:06:02 -03007186 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007187}
7188
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007189static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02007190{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007191 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02007192 struct mgmt_cp_unpair_device *cp = cmd->param;
Johan Hedberga8a1d192011-11-10 15:54:38 +02007193
Johan Hedbergb1078ad2012-02-09 17:21:16 +02007194 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
7195
Johan Hedbergd8b7b1e2014-12-05 13:36:05 +02007196 cmd->cmd_complete(cmd, 0);
Johan Hedberga8a1d192011-11-10 15:54:38 +02007197 mgmt_pending_remove(cmd);
7198}
7199
Johan Hedberg84c61d92014-08-01 11:13:30 +03007200bool mgmt_powering_down(struct hci_dev *hdev)
7201{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007202 struct mgmt_pending_cmd *cmd;
Johan Hedberg84c61d92014-08-01 11:13:30 +03007203 struct mgmt_mode *cp;
7204
7205 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
7206 if (!cmd)
7207 return false;
7208
7209 cp = cmd->param;
7210 if (!cp->val)
7211 return true;
7212
7213 return false;
7214}
7215
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007216void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007217 u8 link_type, u8 addr_type, u8 reason,
7218 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02007219{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007220 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007221 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007222
Johan Hedberg84c61d92014-08-01 11:13:30 +03007223 /* The connection is still in hci_conn_hash so test for 1
7224 * instead of 0 to know if this is the last one.
7225 */
7226 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7227 cancel_delayed_work(&hdev->power_off);
7228 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg8b064a32014-02-24 14:52:22 +02007229 }
7230
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02007231 if (!mgmt_connected)
7232 return;
7233
Andre Guedes57eb7762013-10-30 19:01:41 -03007234 if (link_type != ACL_LINK && link_type != LE_LINK)
7235 return;
7236
Johan Hedberg744cf192011-11-08 20:40:14 +02007237 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02007238
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02007239 bacpy(&ev.addr.bdaddr, bdaddr);
7240 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7241 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02007242
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07007243 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007244
7245 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01007246 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007247
Johan Hedberg124f6e32012-02-09 13:50:12 +02007248 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007249 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007250}
7251
Marcel Holtmann78929242013-10-06 23:55:47 -07007252void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
7253 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02007254{
Andre Guedes3655bba2013-10-30 19:01:40 -03007255 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
7256 struct mgmt_cp_disconnect *cp;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007257 struct mgmt_pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007258
Jefferson Delfes36a75f12012-09-18 13:36:54 -04007259 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
7260 hdev);
7261
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007262 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02007263 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07007264 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02007265
Andre Guedes3655bba2013-10-30 19:01:40 -03007266 cp = cmd->param;
7267
7268 if (bacmp(bdaddr, &cp->addr.bdaddr))
7269 return;
7270
7271 if (cp->addr.type != bdaddr_type)
7272 return;
7273
Johan Hedbergf5818c22014-12-05 13:36:02 +02007274 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007275 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02007276}
Johan Hedberg17d5c042011-01-22 06:09:08 +02007277
Marcel Holtmann445608d2013-10-06 23:55:48 -07007278void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7279 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02007280{
7281 struct mgmt_ev_connect_failed ev;
Johan Hedbergc9910d02014-02-27 14:35:12 +02007282
Johan Hedberg84c61d92014-08-01 11:13:30 +03007283 /* The connection is still in hci_conn_hash so test for 1
7284 * instead of 0 to know if this is the last one.
7285 */
7286 if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
7287 cancel_delayed_work(&hdev->power_off);
7288 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedbergc9910d02014-02-27 14:35:12 +02007289 }
Johan Hedberg17d5c042011-01-22 06:09:08 +02007290
Johan Hedberg4c659c32011-11-07 23:13:39 +02007291 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007292 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02007293 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007294
Marcel Holtmann445608d2013-10-06 23:55:48 -07007295 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02007296}
Johan Hedberg980e1a52011-01-22 06:10:07 +02007297
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007298void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007299{
7300 struct mgmt_ev_pin_code_request ev;
7301
Johan Hedbergd8457692012-02-17 14:24:57 +02007302 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03007303 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02007304 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007305
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07007306 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007307}
7308
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007309void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7310 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007311{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007312 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007313
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007314 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007315 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07007316 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007317
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007318 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007319 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007320}
7321
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007322void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
7323 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02007324{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007325 struct mgmt_pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007326
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007327 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007328 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07007329 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02007330
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007331 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007332 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02007333}
Johan Hedberga5c29682011-02-19 12:05:57 -03007334
Johan Hedberg744cf192011-11-08 20:40:14 +02007335int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg39adbff2014-03-20 08:18:14 +02007336 u8 link_type, u8 addr_type, u32 value,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007337 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03007338{
7339 struct mgmt_ev_user_confirm_request ev;
7340
Johan Hedberg744cf192011-11-08 20:40:14 +02007341 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03007342
Johan Hedberg272d90d2012-02-09 15:26:12 +02007343 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007344 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07007345 ev.confirm_hint = confirm_hint;
Johan Hedberg39adbff2014-03-20 08:18:14 +02007346 ev.value = cpu_to_le32(value);
Johan Hedberga5c29682011-02-19 12:05:57 -03007347
Johan Hedberg744cf192011-11-08 20:40:14 +02007348 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007349 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03007350}
7351
Johan Hedberg272d90d2012-02-09 15:26:12 +02007352int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007353 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08007354{
7355 struct mgmt_ev_user_passkey_request ev;
7356
7357 BT_DBG("%s", hdev->name);
7358
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);
Brian Gix604086b2011-11-23 08:28:33 -08007361
7362 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007363 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08007364}
7365
Brian Gix0df4c182011-11-16 13:53:13 -08007366static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03007367 u8 link_type, u8 addr_type, u8 status,
7368 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03007369{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007370 struct mgmt_pending_cmd *cmd;
Johan Hedberga5c29682011-02-19 12:05:57 -03007371
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007372 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03007373 if (!cmd)
7374 return -ENOENT;
7375
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007376 cmd->cmd_complete(cmd, mgmt_status(status));
Johan Hedberga664b5b2011-02-19 12:06:02 -03007377 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03007378
Johan Hedberg7776d1d2014-12-05 13:36:03 +02007379 return 0;
Johan Hedberga5c29682011-02-19 12:05:57 -03007380}
7381
Johan Hedberg744cf192011-11-08 20:40:14 +02007382int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007383 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007384{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007385 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007386 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007387}
7388
Johan Hedberg272d90d2012-02-09 15:26:12 +02007389int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007390 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03007391{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007392 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007393 status,
7394 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03007395}
Johan Hedberg2a611692011-02-19 12:06:00 -03007396
Brian Gix604086b2011-11-23 08:28:33 -08007397int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007398 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007399{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007400 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007401 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007402}
7403
Johan Hedberg272d90d2012-02-09 15:26:12 +02007404int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007405 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08007406{
Johan Hedberg272d90d2012-02-09 15:26:12 +02007407 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03007408 status,
7409 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08007410}
7411
Johan Hedberg92a25252012-09-06 18:39:26 +03007412int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
7413 u8 link_type, u8 addr_type, u32 passkey,
7414 u8 entered)
7415{
7416 struct mgmt_ev_passkey_notify ev;
7417
7418 BT_DBG("%s", hdev->name);
7419
7420 bacpy(&ev.addr.bdaddr, bdaddr);
7421 ev.addr.type = link_to_bdaddr(link_type, addr_type);
7422 ev.passkey = __cpu_to_le32(passkey);
7423 ev.entered = entered;
7424
7425 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
7426}
7427
Johan Hedberge1e930f2014-09-08 17:09:49 -07007428void mgmt_auth_failed(struct hci_conn *conn, u8 hci_status)
Johan Hedberg2a611692011-02-19 12:06:00 -03007429{
7430 struct mgmt_ev_auth_failed ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007431 struct mgmt_pending_cmd *cmd;
Johan Hedberge1e930f2014-09-08 17:09:49 -07007432 u8 status = mgmt_status(hci_status);
Johan Hedberg2a611692011-02-19 12:06:00 -03007433
Johan Hedberge1e930f2014-09-08 17:09:49 -07007434 bacpy(&ev.addr.bdaddr, &conn->dst);
7435 ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
7436 ev.status = status;
Johan Hedberg2a611692011-02-19 12:06:00 -03007437
Johan Hedberge1e930f2014-09-08 17:09:49 -07007438 cmd = find_pairing(conn);
7439
7440 mgmt_event(MGMT_EV_AUTH_FAILED, conn->hdev, &ev, sizeof(ev),
7441 cmd ? cmd->sk : NULL);
7442
Johan Hedberga511b352014-12-11 21:45:45 +02007443 if (cmd) {
7444 cmd->cmd_complete(cmd, status);
7445 mgmt_pending_remove(cmd);
7446 }
Johan Hedberg2a611692011-02-19 12:06:00 -03007447}
Johan Hedbergb312b1612011-03-16 14:29:37 +02007448
Marcel Holtmann464996a2013-10-15 14:26:24 -07007449void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007450{
7451 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07007452 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007453
7454 if (status) {
7455 u8 mgmt_err = mgmt_status(status);
7456 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007457 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007458 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007459 }
7460
Marcel Holtmann464996a2013-10-15 14:26:24 -07007461 if (test_bit(HCI_AUTH, &hdev->flags))
Marcel Holtmann238be782015-03-13 02:11:06 -07007462 changed = !hci_dev_test_and_set_flag(hdev, HCI_LINK_SECURITY);
Marcel Holtmann464996a2013-10-15 14:26:24 -07007463 else
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007464 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
Johan Hedberg47990ea2012-02-22 11:58:37 +02007465
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007466 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007467 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007468
Johan Hedberg47990ea2012-02-22 11:58:37 +02007469 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07007470 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007471
7472 if (match.sk)
7473 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02007474}
7475
Johan Hedberg890ea892013-03-15 17:06:52 -05007476static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02007477{
Johan Hedberg890ea892013-03-15 17:06:52 -05007478 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007479 struct hci_cp_write_eir cp;
7480
Johan Hedberg976eb202012-10-24 21:12:01 +03007481 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05007482 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02007483
Johan Hedbergc80da272012-02-22 15:38:48 +02007484 memset(hdev->eir, 0, sizeof(hdev->eir));
7485
Johan Hedbergcacaf522012-02-21 00:52:42 +02007486 memset(&cp, 0, sizeof(cp));
7487
Johan Hedberg890ea892013-03-15 17:06:52 -05007488 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02007489}
7490
Marcel Holtmann3e248562013-10-15 14:26:25 -07007491void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007492{
7493 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05007494 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007495 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007496
7497 if (status) {
7498 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007499
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007500 if (enable && hci_dev_test_and_clear_flag(hdev,
7501 HCI_SSP_ENABLED)) {
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007502 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007503 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007504 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007505
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007506 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
7507 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07007508 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007509 }
7510
7511 if (enable) {
Marcel Holtmann238be782015-03-13 02:11:06 -07007512 changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007513 } else {
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007514 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007515 if (!changed)
Marcel Holtmanna69d8922015-03-13 02:11:05 -07007516 changed = hci_dev_test_and_clear_flag(hdev,
7517 HCI_HS_ENABLED);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07007518 else
Marcel Holtmanna358dc12015-03-13 02:11:02 -07007519 hci_dev_clear_flag(hdev, HCI_HS_ENABLED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007520 }
7521
7522 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
7523
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02007524 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07007525 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007526
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02007527 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007528 sock_put(match.sk);
7529
Johan Hedberg890ea892013-03-15 17:06:52 -05007530 hci_req_init(&req, hdev);
7531
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007532 if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) {
7533 if (hci_dev_test_flag(hdev, HCI_USE_DEBUG_KEYS))
Johan Hedberg37699722014-06-24 14:00:27 +03007534 hci_req_add(&req, HCI_OP_WRITE_SSP_DEBUG_MODE,
7535 sizeof(enable), &enable);
Johan Hedberg890ea892013-03-15 17:06:52 -05007536 update_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007537 } else {
Johan Hedberg890ea892013-03-15 17:06:52 -05007538 clear_eir(&req);
Johan Hedberg37699722014-06-24 14:00:27 +03007539 }
Johan Hedberg890ea892013-03-15 17:06:52 -05007540
7541 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02007542}
7543
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007544static void sk_lookup(struct mgmt_pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02007545{
7546 struct cmd_lookup *match = data;
7547
Johan Hedberg90e70452012-02-23 23:09:40 +02007548 if (match->sk == NULL) {
7549 match->sk = cmd->sk;
7550 sock_hold(match->sk);
7551 }
Johan Hedberg90e70452012-02-23 23:09:40 +02007552}
7553
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07007554void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7555 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007556{
Johan Hedberg90e70452012-02-23 23:09:40 +02007557 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007558
Johan Hedberg92da6092013-03-15 17:06:55 -05007559 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
7560 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7561 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02007562
7563 if (!status)
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007564 mgmt_generic_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
7565 dev_class, 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02007566
7567 if (match.sk)
7568 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01007569}
7570
Marcel Holtmann7667da32013-10-15 14:26:27 -07007571void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02007572{
Johan Hedbergb312b1612011-03-16 14:29:37 +02007573 struct mgmt_cp_set_local_name ev;
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007574 struct mgmt_pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007575
Johan Hedberg13928972013-03-15 17:07:00 -05007576 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07007577 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007578
7579 memset(&ev, 0, sizeof(ev));
7580 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02007581 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007582
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007583 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05007584 if (!cmd) {
7585 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02007586
Johan Hedberg13928972013-03-15 17:07:00 -05007587 /* If this is a HCI command related to powering on the
7588 * HCI dev don't send any mgmt signals.
7589 */
7590 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07007591 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02007592 }
7593
Marcel Holtmannf6b77122015-03-14 19:28:05 -07007594 mgmt_generic_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7595 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02007596}
Szymon Jancc35938b2011-03-22 13:12:21 +01007597
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007598void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
Johan Hedberg38da1702014-11-17 20:52:20 +02007599 u8 *rand192, u8 *hash256, u8 *rand256,
7600 u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01007601{
Johan Hedberg3b0602c2015-03-06 21:08:55 +02007602 struct mgmt_pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01007603
Johan Hedberg744cf192011-11-08 20:40:14 +02007604 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01007605
Johan Hedberg2e58ef32011-11-08 20:40:15 +02007606 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01007607 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07007608 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01007609
7610 if (status) {
Johan Hedberga69e8372015-03-06 21:08:53 +02007611 mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
7612 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01007613 } else {
Johan Hedberg66f096f2015-02-02 13:23:42 +02007614 struct mgmt_rp_read_local_oob_data rp;
7615 size_t rp_size = sizeof(rp);
7616
7617 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
7618 memcpy(rp.rand192, rand192, sizeof(rp.rand192));
7619
Johan Hedberg710f11c2014-05-26 11:21:22 +03007620 if (bredr_sc_enabled(hdev) && hash256 && rand256) {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007621 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
Johan Hedberg38da1702014-11-17 20:52:20 +02007622 memcpy(rp.rand256, rand256, sizeof(rp.rand256));
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007623 } else {
Johan Hedberg66f096f2015-02-02 13:23:42 +02007624 rp_size -= sizeof(rp.hash256) + sizeof(rp.rand256);
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08007625 }
Johan Hedberg66f096f2015-02-02 13:23:42 +02007626
Johan Hedberg2a1afb52015-03-06 21:08:54 +02007627 mgmt_cmd_complete(cmd->sk, hdev->id,
7628 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
7629 &rp, rp_size);
Szymon Jancc35938b2011-03-22 13:12:21 +01007630 }
7631
7632 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01007633}
Johan Hedberge17acd42011-03-30 23:57:16 +03007634
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007635static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])
7636{
7637 int i;
7638
7639 for (i = 0; i < uuid_count; i++) {
7640 if (!memcmp(uuid, uuids[i], 16))
7641 return true;
7642 }
7643
7644 return false;
7645}
7646
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007647static bool eir_has_uuids(u8 *eir, u16 eir_len, u16 uuid_count, u8 (*uuids)[16])
7648{
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007649 u16 parsed = 0;
7650
7651 while (parsed < eir_len) {
7652 u8 field_len = eir[0];
7653 u8 uuid[16];
7654 int i;
7655
7656 if (field_len == 0)
7657 break;
7658
7659 if (eir_len - parsed < field_len + 1)
7660 break;
7661
7662 switch (eir[1]) {
7663 case EIR_UUID16_ALL:
7664 case EIR_UUID16_SOME:
7665 for (i = 0; i + 3 <= field_len; i += 2) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007666 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007667 uuid[13] = eir[i + 3];
7668 uuid[12] = eir[i + 2];
7669 if (has_uuid(uuid, uuid_count, uuids))
7670 return true;
7671 }
7672 break;
7673 case EIR_UUID32_ALL:
7674 case EIR_UUID32_SOME:
7675 for (i = 0; i + 5 <= field_len; i += 4) {
Johan Hedberg189f6ad2014-12-05 13:40:01 +02007676 memcpy(uuid, bluetooth_base_uuid, 16);
Jakub Pawlowski799ce932014-12-05 10:55:58 +01007677 uuid[15] = eir[i + 5];
7678 uuid[14] = eir[i + 4];
7679 uuid[13] = eir[i + 3];
7680 uuid[12] = eir[i + 2];
7681 if (has_uuid(uuid, uuid_count, uuids))
7682 return true;
7683 }
7684 break;
7685 case EIR_UUID128_ALL:
7686 case EIR_UUID128_SOME:
7687 for (i = 0; i + 17 <= field_len; i += 16) {
7688 memcpy(uuid, eir + i + 2, 16);
7689 if (has_uuid(uuid, uuid_count, uuids))
7690 return true;
7691 }
7692 break;
7693 }
7694
7695 parsed += field_len + 1;
7696 eir += field_len + 1;
7697 }
7698
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007699 return false;
7700}
7701
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007702static void restart_le_scan(struct hci_dev *hdev)
7703{
7704 /* If controller is not scanning we are done. */
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007705 if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007706 return;
7707
7708 if (time_after(jiffies + DISCOV_LE_RESTART_DELAY,
7709 hdev->discovery.scan_start +
7710 hdev->discovery.scan_duration))
7711 return;
7712
7713 queue_delayed_work(hdev->workqueue, &hdev->le_scan_restart,
7714 DISCOV_LE_RESTART_DELAY);
7715}
7716
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007717static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
7718 u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
7719{
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007720 /* If a RSSI threshold has been specified, and
7721 * HCI_QUIRK_STRICT_DUPLICATE_FILTER is not set, then all results with
7722 * a RSSI smaller than the RSSI threshold will be dropped. If the quirk
7723 * is set, let it through for further processing, as we might need to
7724 * restart the scan.
7725 *
7726 * For BR/EDR devices (pre 1.2) providing no RSSI during inquiry,
7727 * the results are also dropped.
7728 */
7729 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7730 (rssi == HCI_RSSI_INVALID ||
7731 (rssi < hdev->discovery.rssi &&
7732 !test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks))))
7733 return false;
7734
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007735 if (hdev->discovery.uuid_count != 0) {
7736 /* If a list of UUIDs is provided in filter, results with no
7737 * matching UUID should be dropped.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007738 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007739 if (!eir_has_uuids(eir, eir_len, hdev->discovery.uuid_count,
7740 hdev->discovery.uuids) &&
7741 !eir_has_uuids(scan_rsp, scan_rsp_len,
7742 hdev->discovery.uuid_count,
7743 hdev->discovery.uuids))
7744 return false;
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007745 }
7746
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007747 /* If duplicate filtering does not report RSSI changes, then restart
7748 * scanning to ensure updated result with updated RSSI values.
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007749 */
Jakub Pawlowski2976cde2015-03-04 16:24:25 -08007750 if (test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks)) {
7751 restart_le_scan(hdev);
7752
7753 /* Validate RSSI value against the RSSI threshold once more. */
7754 if (hdev->discovery.rssi != HCI_RSSI_INVALID &&
7755 rssi < hdev->discovery.rssi)
7756 return false;
7757 }
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007758
7759 return true;
7760}
7761
Marcel Holtmann901801b2013-10-06 23:55:51 -07007762void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Marcel Holtmannaf589252014-07-01 14:11:20 +02007763 u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
7764 u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03007765{
Johan Hedberge319d2e2012-01-15 19:51:59 +02007766 char buf[512];
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007767 struct mgmt_ev_device_found *ev = (void *)buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02007768 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03007769
Johan Hedberg75ce2082014-07-02 22:42:01 +03007770 /* Don't send events for a non-kernel initiated discovery. With
7771 * LE one exception is if we have pend_le_reports > 0 in which
7772 * case we're doing passive scanning and want these events.
7773 */
7774 if (!hci_discovery_active(hdev)) {
7775 if (link_type == ACL_LINK)
7776 return;
Johan Hedberg66f84552014-07-04 12:37:18 +03007777 if (link_type == LE_LINK && list_empty(&hdev->pend_le_reports))
Johan Hedberg75ce2082014-07-02 22:42:01 +03007778 return;
7779 }
Andre Guedes12602d02013-04-30 15:29:40 -03007780
Jakub Pawlowski82f8b652015-03-04 16:24:26 -08007781 if (hdev->discovery.result_filtering) {
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007782 /* We are using service discovery */
7783 if (!is_filter_match(hdev, rssi, eir, eir_len, scan_rsp,
7784 scan_rsp_len))
7785 return;
7786 }
Marcel Holtmannbda157a2014-12-05 10:55:56 +01007787
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007788 /* Make sure that the buffer is big enough. The 5 extra bytes
7789 * are for the potential CoD field.
7790 */
7791 if (sizeof(*ev) + eir_len + scan_rsp_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07007792 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03007793
Johan Hedberg1dc06092012-01-15 21:01:23 +02007794 memset(buf, 0, sizeof(buf));
7795
Marcel Holtmannda25cf62014-12-05 13:03:35 +01007796 /* In case of device discovery with BR/EDR devices (pre 1.2), the
7797 * RSSI value was reported as 0 when not available. This behavior
7798 * is kept when using device discovery. This is required for full
7799 * backwards compatibility with the API.
7800 *
7801 * However when using service discovery, the value 127 will be
7802 * returned when the RSSI is not available.
7803 */
Szymon Janc91200e92015-01-22 16:57:05 +01007804 if (rssi == HCI_RSSI_INVALID && !hdev->discovery.report_invalid_rssi &&
7805 link_type == ACL_LINK)
Marcel Holtmannefb25132014-12-05 13:03:34 +01007806 rssi = 0;
7807
Johan Hedberg841c5642014-07-07 12:45:54 +03007808 bacpy(&ev->addr.bdaddr, bdaddr);
7809 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02007810 ev->rssi = rssi;
Marcel Holtmannaf589252014-07-01 14:11:20 +02007811 ev->flags = cpu_to_le32(flags);
Johan Hedberge17acd42011-03-30 23:57:16 +03007812
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007813 if (eir_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007814 /* Copy EIR or advertising data into event */
Johan Hedberge319d2e2012-01-15 19:51:59 +02007815 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03007816
Johan Hedberg1dc06092012-01-15 21:01:23 +02007817 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
7818 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007819 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02007820
Jakub Pawlowski48f86b72015-03-04 16:24:24 -08007821 if (scan_rsp_len > 0)
Marcel Holtmannb487b9c2014-12-05 10:55:57 +01007822 /* Append scan response data to event */
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007823 memcpy(ev->eir + eir_len, scan_rsp, scan_rsp_len);
Jakub Pawlowski4b0e0ce2015-02-01 23:07:55 -08007824
Johan Hedberg5d2e9fa2014-03-25 10:30:47 +02007825 ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
7826 ev_size = sizeof(*ev) + eir_len + scan_rsp_len;
Andre Guedesf8523592011-09-09 18:56:26 -03007827
Marcel Holtmann901801b2013-10-06 23:55:51 -07007828 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03007829}
Johan Hedberga88a9652011-03-30 13:18:12 +03007830
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007831void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
7832 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03007833{
Johan Hedbergb644ba32012-01-17 21:48:47 +02007834 struct mgmt_ev_device_found *ev;
7835 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
7836 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03007837
Johan Hedbergb644ba32012-01-17 21:48:47 +02007838 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03007839
Johan Hedbergb644ba32012-01-17 21:48:47 +02007840 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03007841
Johan Hedbergb644ba32012-01-17 21:48:47 +02007842 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03007843 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007844 ev->rssi = rssi;
7845
7846 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03007847 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007848
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02007849 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02007850
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07007851 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03007852}
Johan Hedberg314b2382011-04-27 10:29:57 -04007853
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007854void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04007855{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007856 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02007857
Andre Guedes343fb142011-11-22 17:14:19 -03007858 BT_DBG("%s discovering %u", hdev->name, discovering);
7859
Johan Hedbergf963e8e2012-02-20 23:30:44 +02007860 memset(&ev, 0, sizeof(ev));
7861 ev.type = hdev->discovery.type;
7862 ev.discovering = discovering;
7863
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07007864 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04007865}
Antti Julku5e762442011-08-25 16:48:02 +03007866
Marcel Holtmann1904a852015-01-11 13:50:44 -08007867static void adv_enable_complete(struct hci_dev *hdev, u8 status, u16 opcode)
Marcel Holtmann5976e602013-10-06 04:08:14 -07007868{
7869 BT_DBG("%s status %u", hdev->name, status);
Marcel Holtmann5976e602013-10-06 04:08:14 -07007870}
7871
7872void mgmt_reenable_advertising(struct hci_dev *hdev)
7873{
7874 struct hci_request req;
7875
Marcel Holtmannd7a5a112015-03-13 02:11:00 -07007876 if (!hci_dev_test_flag(hdev, HCI_ADVERTISING))
Marcel Holtmann5976e602013-10-06 04:08:14 -07007877 return;
7878
7879 hci_req_init(&req, hdev);
7880 enable_advertising(&req);
Johan Hedberg0ec5ae82014-07-08 15:07:50 +03007881 hci_req_run(&req, adv_enable_complete);
Marcel Holtmann5976e602013-10-06 04:08:14 -07007882}
Johan Hedberg6d785aa32015-03-06 21:08:51 +02007883
7884static struct hci_mgmt_chan chan = {
7885 .channel = HCI_CHANNEL_CONTROL,
7886 .handler_count = ARRAY_SIZE(mgmt_handlers),
7887 .handlers = mgmt_handlers,
7888};
7889
7890int mgmt_init(void)
7891{
7892 return hci_mgmt_chan_register(&chan);
7893}
7894
7895void mgmt_exit(void)
7896{
7897 hci_mgmt_chan_unregister(&chan);
7898}