blob: 301b18a1c6a0cec9635cf12e494b205f1901d8cc [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>
32#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070033
34#include "smp.h"
Johan Hedberg03811012010-12-08 00:21:06 +020035
Johan Hedberg2da9c552012-02-17 14:39:28 +020036#define MGMT_VERSION 1
Marcel Holtmann40456642014-01-28 15:39:01 -080037#define MGMT_REVISION 5
Johan Hedberg02d98122010-12-13 21:07:04 +020038
Johan Hedberge70bb2e2012-02-13 16:59:33 +020039static const u16 mgmt_commands[] = {
40 MGMT_OP_READ_INDEX_LIST,
41 MGMT_OP_READ_INFO,
42 MGMT_OP_SET_POWERED,
43 MGMT_OP_SET_DISCOVERABLE,
44 MGMT_OP_SET_CONNECTABLE,
45 MGMT_OP_SET_FAST_CONNECTABLE,
46 MGMT_OP_SET_PAIRABLE,
47 MGMT_OP_SET_LINK_SECURITY,
48 MGMT_OP_SET_SSP,
49 MGMT_OP_SET_HS,
50 MGMT_OP_SET_LE,
51 MGMT_OP_SET_DEV_CLASS,
52 MGMT_OP_SET_LOCAL_NAME,
53 MGMT_OP_ADD_UUID,
54 MGMT_OP_REMOVE_UUID,
55 MGMT_OP_LOAD_LINK_KEYS,
56 MGMT_OP_LOAD_LONG_TERM_KEYS,
57 MGMT_OP_DISCONNECT,
58 MGMT_OP_GET_CONNECTIONS,
59 MGMT_OP_PIN_CODE_REPLY,
60 MGMT_OP_PIN_CODE_NEG_REPLY,
61 MGMT_OP_SET_IO_CAPABILITY,
62 MGMT_OP_PAIR_DEVICE,
63 MGMT_OP_CANCEL_PAIR_DEVICE,
64 MGMT_OP_UNPAIR_DEVICE,
65 MGMT_OP_USER_CONFIRM_REPLY,
66 MGMT_OP_USER_CONFIRM_NEG_REPLY,
67 MGMT_OP_USER_PASSKEY_REPLY,
68 MGMT_OP_USER_PASSKEY_NEG_REPLY,
69 MGMT_OP_READ_LOCAL_OOB_DATA,
70 MGMT_OP_ADD_REMOTE_OOB_DATA,
71 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
72 MGMT_OP_START_DISCOVERY,
73 MGMT_OP_STOP_DISCOVERY,
74 MGMT_OP_CONFIRM_NAME,
75 MGMT_OP_BLOCK_DEVICE,
76 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070077 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030078 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030079 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070080 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070081 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080082 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080083 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberg41edf162014-02-18 10:19:35 +020084 MGMT_OP_LOAD_IRKS,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020085};
86
87static const u16 mgmt_events[] = {
88 MGMT_EV_CONTROLLER_ERROR,
89 MGMT_EV_INDEX_ADDED,
90 MGMT_EV_INDEX_REMOVED,
91 MGMT_EV_NEW_SETTINGS,
92 MGMT_EV_CLASS_OF_DEV_CHANGED,
93 MGMT_EV_LOCAL_NAME_CHANGED,
94 MGMT_EV_NEW_LINK_KEY,
95 MGMT_EV_NEW_LONG_TERM_KEY,
96 MGMT_EV_DEVICE_CONNECTED,
97 MGMT_EV_DEVICE_DISCONNECTED,
98 MGMT_EV_CONNECT_FAILED,
99 MGMT_EV_PIN_CODE_REQUEST,
100 MGMT_EV_USER_CONFIRM_REQUEST,
101 MGMT_EV_USER_PASSKEY_REQUEST,
102 MGMT_EV_AUTH_FAILED,
103 MGMT_EV_DEVICE_FOUND,
104 MGMT_EV_DISCOVERING,
105 MGMT_EV_DEVICE_BLOCKED,
106 MGMT_EV_DEVICE_UNBLOCKED,
107 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300108 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800109 MGMT_EV_NEW_IRK,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200110};
111
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800112#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200113
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200114#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
115 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
116
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200117struct pending_cmd {
118 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200119 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200120 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100121 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200122 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300123 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124};
125
Johan Hedbergca69b792011-11-11 18:10:00 +0200126/* HCI to MGMT error code conversion table */
127static u8 mgmt_status_table[] = {
128 MGMT_STATUS_SUCCESS,
129 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
130 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
131 MGMT_STATUS_FAILED, /* Hardware Failure */
132 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
133 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200134 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200135 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
136 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
137 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
138 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
139 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
140 MGMT_STATUS_BUSY, /* Command Disallowed */
141 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
142 MGMT_STATUS_REJECTED, /* Rejected Security */
143 MGMT_STATUS_REJECTED, /* Rejected Personal */
144 MGMT_STATUS_TIMEOUT, /* Host Timeout */
145 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
146 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
147 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
148 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
149 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
150 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
151 MGMT_STATUS_BUSY, /* Repeated Attempts */
152 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
153 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
154 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
155 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
156 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
157 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
158 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
159 MGMT_STATUS_FAILED, /* Unspecified Error */
160 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
161 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
162 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
163 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
164 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
165 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
166 MGMT_STATUS_FAILED, /* Unit Link Key Used */
167 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
168 MGMT_STATUS_TIMEOUT, /* Instant Passed */
169 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
170 MGMT_STATUS_FAILED, /* Transaction Collision */
171 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
172 MGMT_STATUS_REJECTED, /* QoS Rejected */
173 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
174 MGMT_STATUS_REJECTED, /* Insufficient Security */
175 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
176 MGMT_STATUS_BUSY, /* Role Switch Pending */
177 MGMT_STATUS_FAILED, /* Slot Violation */
178 MGMT_STATUS_FAILED, /* Role Switch Failed */
179 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
180 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
181 MGMT_STATUS_BUSY, /* Host Busy Pairing */
182 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
183 MGMT_STATUS_BUSY, /* Controller Busy */
184 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
185 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
186 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
187 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
188 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
189};
190
191static u8 mgmt_status(u8 hci_status)
192{
193 if (hci_status < ARRAY_SIZE(mgmt_status_table))
194 return mgmt_status_table[hci_status];
195
196 return MGMT_STATUS_FAILED;
197}
198
Szymon Janc4e51eae2011-02-25 19:05:48 +0100199static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200200{
201 struct sk_buff *skb;
202 struct mgmt_hdr *hdr;
203 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300204 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200205
Szymon Janc34eb5252011-02-28 14:10:08 +0100206 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200207
Andre Guedes790eff42012-06-07 19:05:46 -0300208 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200209 if (!skb)
210 return -ENOMEM;
211
212 hdr = (void *) skb_put(skb, sizeof(*hdr));
213
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530214 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100215 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200216 hdr->len = cpu_to_le16(sizeof(*ev));
217
218 ev = (void *) skb_put(skb, sizeof(*ev));
219 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200220 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200221
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300222 err = sock_queue_rcv_skb(sk, skb);
223 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200224 kfree_skb(skb);
225
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300226 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200227}
228
Johan Hedbergaee9b212012-02-18 15:07:59 +0200229static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300230 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200231{
232 struct sk_buff *skb;
233 struct mgmt_hdr *hdr;
234 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300235 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200236
237 BT_DBG("sock %p", sk);
238
Andre Guedes790eff42012-06-07 19:05:46 -0300239 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200240 if (!skb)
241 return -ENOMEM;
242
243 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200244
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530245 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100246 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200247 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200248
Johan Hedberga38528f2011-01-22 06:46:43 +0200249 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200250 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200251 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100252
253 if (rp)
254 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200255
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300256 err = sock_queue_rcv_skb(sk, skb);
257 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200258 kfree_skb(skb);
259
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100260 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200261}
262
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300263static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
264 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200265{
266 struct mgmt_rp_read_version rp;
267
268 BT_DBG("sock %p", sk);
269
270 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200271 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200272
Johan Hedbergaee9b212012-02-18 15:07:59 +0200273 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300274 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200275}
276
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300277static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
278 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200279{
280 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200281 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
282 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200283 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200284 size_t rp_size;
285 int i, err;
286
287 BT_DBG("sock %p", sk);
288
289 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
290
291 rp = kmalloc(rp_size, GFP_KERNEL);
292 if (!rp)
293 return -ENOMEM;
294
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200295 rp->num_commands = __constant_cpu_to_le16(num_commands);
296 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200297
298 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
299 put_unaligned_le16(mgmt_commands[i], opcode);
300
301 for (i = 0; i < num_events; i++, opcode++)
302 put_unaligned_le16(mgmt_events[i], opcode);
303
Johan Hedbergaee9b212012-02-18 15:07:59 +0200304 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300305 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200306 kfree(rp);
307
308 return err;
309}
310
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300311static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
312 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200314 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200315 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200316 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200317 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300318 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200319
320 BT_DBG("sock %p", sk);
321
322 read_lock(&hci_dev_list_lock);
323
324 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300325 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700326 if (d->dev_type == HCI_BREDR)
327 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200328 }
329
Johan Hedberga38528f2011-01-22 06:46:43 +0200330 rp_len = sizeof(*rp) + (2 * count);
331 rp = kmalloc(rp_len, GFP_ATOMIC);
332 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100333 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200334 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100335 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200336
Johan Hedberg476e44c2012-10-19 20:10:46 +0300337 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200338 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200339 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200340 continue;
341
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700342 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
343 continue;
344
Marcel Holtmann1514b892013-10-06 08:25:01 -0700345 if (d->dev_type == HCI_BREDR) {
346 rp->index[count++] = cpu_to_le16(d->id);
347 BT_DBG("Added hci%u", d->id);
348 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349 }
350
Johan Hedberg476e44c2012-10-19 20:10:46 +0300351 rp->num_controllers = cpu_to_le16(count);
352 rp_len = sizeof(*rp) + (2 * count);
353
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354 read_unlock(&hci_dev_list_lock);
355
Johan Hedbergaee9b212012-02-18 15:07:59 +0200356 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300357 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200358
Johan Hedberga38528f2011-01-22 06:46:43 +0200359 kfree(rp);
360
361 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200362}
363
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200365{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200367
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200368 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200369 settings |= MGMT_SETTING_PAIRABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800370 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Andre Guedesed3fa312012-07-24 15:03:46 -0300372 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300373 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500374 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
375 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300376 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200377 settings |= MGMT_SETTING_BREDR;
378 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700379
380 if (lmp_ssp_capable(hdev)) {
381 settings |= MGMT_SETTING_SSP;
382 settings |= MGMT_SETTING_HS;
383 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800384
Marcel Holtmann5afeac12014-01-10 02:07:27 -0800385 if (lmp_sc_capable(hdev) ||
386 test_bit(HCI_FORCE_SC, &hdev->dev_flags))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800387 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700388 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100389
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300390 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200391 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300392 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200393 settings |= MGMT_SETTING_PRIVACY;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300394 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200395
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200396 return settings;
397}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200398
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399static u32 get_current_settings(struct hci_dev *hdev)
400{
401 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200402
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200403 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100404 settings |= MGMT_SETTING_POWERED;
405
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200406 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200407 settings |= MGMT_SETTING_CONNECTABLE;
408
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500409 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
410 settings |= MGMT_SETTING_FAST_CONNECTABLE;
411
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200412 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200413 settings |= MGMT_SETTING_DISCOVERABLE;
414
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200415 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200416 settings |= MGMT_SETTING_PAIRABLE;
417
Johan Hedberg56f87902013-10-02 13:43:13 +0300418 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200419 settings |= MGMT_SETTING_BREDR;
420
Johan Hedberg06199cf2012-02-22 16:37:11 +0200421 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200423
Johan Hedberg47990ea2012-02-22 11:58:37 +0200424 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200425 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200426
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200427 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200428 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200429
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200430 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
431 settings |= MGMT_SETTING_HS;
432
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200433 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300434 settings |= MGMT_SETTING_ADVERTISING;
435
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800436 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
437 settings |= MGMT_SETTING_SECURE_CONN;
438
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800439 if (test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags))
440 settings |= MGMT_SETTING_DEBUG_KEYS;
441
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200442 if (test_bit(HCI_PRIVACY, &hdev->dev_flags))
443 settings |= MGMT_SETTING_PRIVACY;
444
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200445 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200446}
447
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300448#define PNP_INFO_SVCLASS_ID 0x1200
449
Johan Hedberg213202e2013-01-27 00:31:33 +0200450static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
451{
452 u8 *ptr = data, *uuids_start = NULL;
453 struct bt_uuid *uuid;
454
455 if (len < 4)
456 return ptr;
457
458 list_for_each_entry(uuid, &hdev->uuids, list) {
459 u16 uuid16;
460
461 if (uuid->size != 16)
462 continue;
463
464 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
465 if (uuid16 < 0x1100)
466 continue;
467
468 if (uuid16 == PNP_INFO_SVCLASS_ID)
469 continue;
470
471 if (!uuids_start) {
472 uuids_start = ptr;
473 uuids_start[0] = 1;
474 uuids_start[1] = EIR_UUID16_ALL;
475 ptr += 2;
476 }
477
478 /* Stop if not enough space to put next UUID */
479 if ((ptr - data) + sizeof(u16) > len) {
480 uuids_start[1] = EIR_UUID16_SOME;
481 break;
482 }
483
484 *ptr++ = (uuid16 & 0x00ff);
485 *ptr++ = (uuid16 & 0xff00) >> 8;
486 uuids_start[0] += sizeof(uuid16);
487 }
488
489 return ptr;
490}
491
Johan Hedbergcdf19632013-01-27 00:31:34 +0200492static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
493{
494 u8 *ptr = data, *uuids_start = NULL;
495 struct bt_uuid *uuid;
496
497 if (len < 6)
498 return ptr;
499
500 list_for_each_entry(uuid, &hdev->uuids, list) {
501 if (uuid->size != 32)
502 continue;
503
504 if (!uuids_start) {
505 uuids_start = ptr;
506 uuids_start[0] = 1;
507 uuids_start[1] = EIR_UUID32_ALL;
508 ptr += 2;
509 }
510
511 /* Stop if not enough space to put next UUID */
512 if ((ptr - data) + sizeof(u32) > len) {
513 uuids_start[1] = EIR_UUID32_SOME;
514 break;
515 }
516
517 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
518 ptr += sizeof(u32);
519 uuids_start[0] += sizeof(u32);
520 }
521
522 return ptr;
523}
524
Johan Hedbergc00d5752013-01-27 00:31:35 +0200525static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
526{
527 u8 *ptr = data, *uuids_start = NULL;
528 struct bt_uuid *uuid;
529
530 if (len < 18)
531 return ptr;
532
533 list_for_each_entry(uuid, &hdev->uuids, list) {
534 if (uuid->size != 128)
535 continue;
536
537 if (!uuids_start) {
538 uuids_start = ptr;
539 uuids_start[0] = 1;
540 uuids_start[1] = EIR_UUID128_ALL;
541 ptr += 2;
542 }
543
544 /* Stop if not enough space to put next UUID */
545 if ((ptr - data) + 16 > len) {
546 uuids_start[1] = EIR_UUID128_SOME;
547 break;
548 }
549
550 memcpy(ptr, uuid->uuid, 16);
551 ptr += 16;
552 uuids_start[0] += 16;
553 }
554
555 return ptr;
556}
557
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300558static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
559{
560 struct pending_cmd *cmd;
561
562 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
563 if (cmd->opcode == opcode)
564 return cmd;
565 }
566
567 return NULL;
568}
569
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700570static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
571{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700572 u8 ad_len = 0;
573 size_t name_len;
574
575 name_len = strlen(hdev->dev_name);
576 if (name_len > 0) {
577 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
578
579 if (name_len > max_len) {
580 name_len = max_len;
581 ptr[1] = EIR_NAME_SHORT;
582 } else
583 ptr[1] = EIR_NAME_COMPLETE;
584
585 ptr[0] = name_len + 1;
586
587 memcpy(ptr + 2, hdev->dev_name, name_len);
588
589 ad_len += (name_len + 2);
590 ptr += (name_len + 2);
591 }
592
593 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700594}
595
596static void update_scan_rsp_data(struct hci_request *req)
597{
598 struct hci_dev *hdev = req->hdev;
599 struct hci_cp_le_set_scan_rsp_data cp;
600 u8 len;
601
Johan Hedberg7751ef12013-10-19 23:38:15 +0300602 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700603 return;
604
605 memset(&cp, 0, sizeof(cp));
606
607 len = create_scan_rsp_data(hdev, cp.data);
608
Johan Hedbergeb438b52013-10-16 15:31:07 +0300609 if (hdev->scan_rsp_data_len == len &&
610 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700611 return;
612
Johan Hedbergeb438b52013-10-16 15:31:07 +0300613 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
614 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700615
616 cp.length = len;
617
618 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
619}
620
Johan Hedberg9a43e252013-10-20 19:00:07 +0300621static u8 get_adv_discov_flags(struct hci_dev *hdev)
622{
623 struct pending_cmd *cmd;
624
625 /* If there's a pending mgmt command the flags will not yet have
626 * their final values, so check for this first.
627 */
628 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
629 if (cmd) {
630 struct mgmt_mode *cp = cmd->param;
631 if (cp->val == 0x01)
632 return LE_AD_GENERAL;
633 else if (cp->val == 0x02)
634 return LE_AD_LIMITED;
635 } else {
636 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
637 return LE_AD_LIMITED;
638 else if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
639 return LE_AD_GENERAL;
640 }
641
642 return 0;
643}
644
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700645static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700646{
647 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700648
Johan Hedberg9a43e252013-10-20 19:00:07 +0300649 flags |= get_adv_discov_flags(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700650
Johan Hedberge8340042014-01-30 11:16:50 -0800651 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700652 flags |= LE_AD_NO_BREDR;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700653
654 if (flags) {
655 BT_DBG("adv flags 0x%02x", flags);
656
657 ptr[0] = 2;
658 ptr[1] = EIR_FLAGS;
659 ptr[2] = flags;
660
661 ad_len += 3;
662 ptr += 3;
663 }
664
665 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
666 ptr[0] = 2;
667 ptr[1] = EIR_TX_POWER;
668 ptr[2] = (u8) hdev->adv_tx_power;
669
670 ad_len += 3;
671 ptr += 3;
672 }
673
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700674 return ad_len;
675}
676
Marcel Holtmann5947f4b2013-10-16 00:16:50 -0700677static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700678{
679 struct hci_dev *hdev = req->hdev;
680 struct hci_cp_le_set_adv_data cp;
681 u8 len;
682
Johan Hedberg10994ce2013-10-19 23:38:16 +0300683 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700684 return;
685
686 memset(&cp, 0, sizeof(cp));
687
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700688 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700689
690 if (hdev->adv_data_len == len &&
691 memcmp(cp.data, hdev->adv_data, len) == 0)
692 return;
693
694 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
695 hdev->adv_data_len = len;
696
697 cp.length = len;
698
699 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
700}
701
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300702static void create_eir(struct hci_dev *hdev, u8 *data)
703{
704 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300705 size_t name_len;
706
707 name_len = strlen(hdev->dev_name);
708
709 if (name_len > 0) {
710 /* EIR Data type */
711 if (name_len > 48) {
712 name_len = 48;
713 ptr[1] = EIR_NAME_SHORT;
714 } else
715 ptr[1] = EIR_NAME_COMPLETE;
716
717 /* EIR Data length */
718 ptr[0] = name_len + 1;
719
720 memcpy(ptr + 2, hdev->dev_name, name_len);
721
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300722 ptr += (name_len + 2);
723 }
724
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100725 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700726 ptr[0] = 2;
727 ptr[1] = EIR_TX_POWER;
728 ptr[2] = (u8) hdev->inq_tx_power;
729
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700730 ptr += 3;
731 }
732
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700733 if (hdev->devid_source > 0) {
734 ptr[0] = 9;
735 ptr[1] = EIR_DEVICE_ID;
736
737 put_unaligned_le16(hdev->devid_source, ptr + 2);
738 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
739 put_unaligned_le16(hdev->devid_product, ptr + 6);
740 put_unaligned_le16(hdev->devid_version, ptr + 8);
741
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700742 ptr += 10;
743 }
744
Johan Hedberg213202e2013-01-27 00:31:33 +0200745 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200746 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200747 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300748}
749
Johan Hedberg890ea892013-03-15 17:06:52 -0500750static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300751{
Johan Hedberg890ea892013-03-15 17:06:52 -0500752 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300753 struct hci_cp_write_eir cp;
754
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200755 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500756 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200757
Johan Hedberg976eb202012-10-24 21:12:01 +0300758 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500759 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300760
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200761 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500762 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300763
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200764 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500765 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300766
767 memset(&cp, 0, sizeof(cp));
768
769 create_eir(hdev, cp.data);
770
771 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500772 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300773
774 memcpy(hdev->eir, cp.data, sizeof(cp.data));
775
Johan Hedberg890ea892013-03-15 17:06:52 -0500776 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300777}
778
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200779static u8 get_service_classes(struct hci_dev *hdev)
780{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300781 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200782 u8 val = 0;
783
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300784 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200785 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200786
787 return val;
788}
789
Johan Hedberg890ea892013-03-15 17:06:52 -0500790static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200791{
Johan Hedberg890ea892013-03-15 17:06:52 -0500792 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200793 u8 cod[3];
794
795 BT_DBG("%s", hdev->name);
796
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200797 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500798 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200799
Johan Hedbergf87ea1d2013-10-19 23:38:17 +0300800 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
801 return;
802
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200803 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500804 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200805
806 cod[0] = hdev->minor_class;
807 cod[1] = hdev->major_class;
808 cod[2] = get_service_classes(hdev);
809
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700810 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
811 cod[1] |= 0x20;
812
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200813 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500814 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200815
Johan Hedberg890ea892013-03-15 17:06:52 -0500816 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200817}
818
Johan Hedberg199a2fb2014-02-22 19:06:33 +0200819static u8 get_adv_type(struct hci_dev *hdev)
820{
821 struct pending_cmd *cmd;
822 bool connectable;
823
824 /* If there's a pending mgmt command the flag will not yet have
825 * it's final value, so check for this first.
826 */
827 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
828 if (cmd) {
829 struct mgmt_mode *cp = cmd->param;
830 connectable = !!cp->val;
831 } else {
832 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
833 }
834
835 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
836}
837
838static void enable_advertising(struct hci_request *req)
839{
840 struct hci_dev *hdev = req->hdev;
841 struct hci_cp_le_set_adv_param cp;
842 u8 enable = 0x01;
843
844 memset(&cp, 0, sizeof(cp));
845 cp.min_interval = __constant_cpu_to_le16(0x0800);
846 cp.max_interval = __constant_cpu_to_le16(0x0800);
847 cp.type = get_adv_type(hdev);
848 cp.own_address_type = hdev->own_addr_type;
849 cp.channel_map = hdev->le_adv_channel_map;
850
851 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
852
853 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
854}
855
856static void disable_advertising(struct hci_request *req)
857{
858 u8 enable = 0x00;
859
860 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
861}
862
Johan Hedberg7d785252011-12-15 00:47:39 +0200863static void service_cache_off(struct work_struct *work)
864{
865 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300866 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500867 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200868
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200869 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200870 return;
871
Johan Hedberg890ea892013-03-15 17:06:52 -0500872 hci_req_init(&req, hdev);
873
Johan Hedberg7d785252011-12-15 00:47:39 +0200874 hci_dev_lock(hdev);
875
Johan Hedberg890ea892013-03-15 17:06:52 -0500876 update_eir(&req);
877 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200878
879 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500880
881 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200882}
883
Johan Hedberg6a919082012-02-28 06:17:26 +0200884static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200885{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200886 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200887 return;
888
Johan Hedberg4f87da82012-03-02 19:55:56 +0200889 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200890
Johan Hedberg4f87da82012-03-02 19:55:56 +0200891 /* Non-mgmt controlled devices get this bit set
892 * implicitly so that pairing works for them, however
893 * for mgmt we require user-space to explicitly enable
894 * it
895 */
896 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200897}
898
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200899static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300900 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200901{
902 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200903
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200904 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200905
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300906 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200907
Johan Hedberg03811012010-12-08 00:21:06 +0200908 memset(&rp, 0, sizeof(rp));
909
Johan Hedberg03811012010-12-08 00:21:06 +0200910 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200911
912 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200913 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200914
915 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
916 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
917
918 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200919
920 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200921 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200922
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300923 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200924
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200925 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300926 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200927}
928
929static void mgmt_pending_free(struct pending_cmd *cmd)
930{
931 sock_put(cmd->sk);
932 kfree(cmd->param);
933 kfree(cmd);
934}
935
936static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300937 struct hci_dev *hdev, void *data,
938 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200939{
940 struct pending_cmd *cmd;
941
Andre Guedes12b94562012-06-07 19:05:45 -0300942 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200943 if (!cmd)
944 return NULL;
945
946 cmd->opcode = opcode;
947 cmd->index = hdev->id;
948
Andre Guedes12b94562012-06-07 19:05:45 -0300949 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200950 if (!cmd->param) {
951 kfree(cmd);
952 return NULL;
953 }
954
955 if (data)
956 memcpy(cmd->param, data, len);
957
958 cmd->sk = sk;
959 sock_hold(sk);
960
961 list_add(&cmd->list, &hdev->mgmt_pending);
962
963 return cmd;
964}
965
966static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300967 void (*cb)(struct pending_cmd *cmd,
968 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300969 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200970{
Andre Guedesa3d09352013-02-01 11:21:30 -0300971 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200972
Andre Guedesa3d09352013-02-01 11:21:30 -0300973 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200974 if (opcode > 0 && cmd->opcode != opcode)
975 continue;
976
977 cb(cmd, data);
978 }
979}
980
Johan Hedberg03811012010-12-08 00:21:06 +0200981static void mgmt_pending_remove(struct pending_cmd *cmd)
982{
983 list_del(&cmd->list);
984 mgmt_pending_free(cmd);
985}
986
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200987static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200988{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200989 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200990
Johan Hedbergaee9b212012-02-18 15:07:59 +0200991 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300992 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200993}
994
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200995static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300996 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200997{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300998 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200999 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001000 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001001
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001002 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001003
Johan Hedberga7e80f22013-01-09 16:05:19 +02001004 if (cp->val != 0x00 && cp->val != 0x01)
1005 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1006 MGMT_STATUS_INVALID_PARAMS);
1007
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001008 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001009
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001010 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
1011 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1012 MGMT_STATUS_BUSY);
1013 goto failed;
1014 }
1015
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001016 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
1017 cancel_delayed_work(&hdev->power_off);
1018
1019 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +02001020 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
1021 data, len);
1022 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001023 goto failed;
1024 }
1025 }
1026
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001027 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001028 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001029 goto failed;
1030 }
1031
Johan Hedberg03811012010-12-08 00:21:06 +02001032 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1033 if (!cmd) {
1034 err = -ENOMEM;
1035 goto failed;
1036 }
1037
1038 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +02001039 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +02001040 else
Johan Hedberg19202572013-01-14 22:33:51 +02001041 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +02001042
1043 err = 0;
1044
1045failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001046 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001047 return err;
1048}
1049
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001050static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
1051 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001052{
1053 struct sk_buff *skb;
1054 struct mgmt_hdr *hdr;
1055
Andre Guedes790eff42012-06-07 19:05:46 -03001056 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001057 if (!skb)
1058 return -ENOMEM;
1059
1060 hdr = (void *) skb_put(skb, sizeof(*hdr));
1061 hdr->opcode = cpu_to_le16(event);
1062 if (hdev)
1063 hdr->index = cpu_to_le16(hdev->id);
1064 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05301065 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001066 hdr->len = cpu_to_le16(data_len);
1067
1068 if (data)
1069 memcpy(skb_put(skb, data_len), data, data_len);
1070
Marcel Holtmann97e0bde2012-02-22 13:49:28 +01001071 /* Time stamp */
1072 __net_timestamp(skb);
1073
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001074 hci_send_to_control(skb, skip_sk);
1075 kfree_skb(skb);
1076
1077 return 0;
1078}
1079
1080static int new_settings(struct hci_dev *hdev, struct sock *skip)
1081{
1082 __le32 ev;
1083
1084 ev = cpu_to_le32(get_current_settings(hdev));
1085
1086 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1087}
1088
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001089struct cmd_lookup {
1090 struct sock *sk;
1091 struct hci_dev *hdev;
1092 u8 mgmt_status;
1093};
1094
1095static void settings_rsp(struct pending_cmd *cmd, void *data)
1096{
1097 struct cmd_lookup *match = data;
1098
1099 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1100
1101 list_del(&cmd->list);
1102
1103 if (match->sk == NULL) {
1104 match->sk = cmd->sk;
1105 sock_hold(match->sk);
1106 }
1107
1108 mgmt_pending_free(cmd);
1109}
1110
1111static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1112{
1113 u8 *status = data;
1114
1115 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1116 mgmt_pending_remove(cmd);
1117}
1118
Johan Hedberge6fe7982013-10-02 15:45:22 +03001119static u8 mgmt_bredr_support(struct hci_dev *hdev)
1120{
1121 if (!lmp_bredr_capable(hdev))
1122 return MGMT_STATUS_NOT_SUPPORTED;
1123 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1124 return MGMT_STATUS_REJECTED;
1125 else
1126 return MGMT_STATUS_SUCCESS;
1127}
1128
1129static u8 mgmt_le_support(struct hci_dev *hdev)
1130{
1131 if (!lmp_le_capable(hdev))
1132 return MGMT_STATUS_NOT_SUPPORTED;
1133 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1134 return MGMT_STATUS_REJECTED;
1135 else
1136 return MGMT_STATUS_SUCCESS;
1137}
1138
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001139static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1140{
1141 struct pending_cmd *cmd;
1142 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001143 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001144 bool changed;
1145
1146 BT_DBG("status 0x%02x", status);
1147
1148 hci_dev_lock(hdev);
1149
1150 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1151 if (!cmd)
1152 goto unlock;
1153
1154 if (status) {
1155 u8 mgmt_err = mgmt_status(status);
1156 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001157 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001158 goto remove_cmd;
1159 }
1160
1161 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001162 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001163 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1164 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001165
1166 if (hdev->discov_timeout > 0) {
1167 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1168 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1169 to);
1170 }
1171 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001172 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1173 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001174 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001175
1176 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1177
1178 if (changed)
1179 new_settings(hdev, cmd->sk);
1180
Marcel Holtmann970ba522013-10-15 06:33:57 -07001181 /* When the discoverable mode gets changed, make sure
1182 * that class of device has the limited discoverable
1183 * bit correctly set.
1184 */
1185 hci_req_init(&req, hdev);
1186 update_class(&req);
1187 hci_req_run(&req, NULL);
1188
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001189remove_cmd:
1190 mgmt_pending_remove(cmd);
1191
1192unlock:
1193 hci_dev_unlock(hdev);
1194}
1195
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001196static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001197 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001198{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001199 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001200 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001201 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001202 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001203 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001204 int err;
1205
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001206 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001207
Johan Hedberg9a43e252013-10-20 19:00:07 +03001208 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1209 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001210 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberg9a43e252013-10-20 19:00:07 +03001211 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001212
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001213 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga7e80f22013-01-09 16:05:19 +02001214 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1215 MGMT_STATUS_INVALID_PARAMS);
1216
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001217 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001218
1219 /* Disabling discoverable requires that no timeout is set,
1220 * and enabling limited discoverable requires a timeout.
1221 */
1222 if ((cp->val == 0x00 && timeout > 0) ||
1223 (cp->val == 0x02 && timeout == 0))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001224 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001225 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001226
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001227 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001228
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001229 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001230 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001231 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001232 goto failed;
1233 }
1234
1235 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001236 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001237 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001238 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001239 goto failed;
1240 }
1241
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001242 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001243 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001244 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001245 goto failed;
1246 }
1247
1248 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001249 bool changed = false;
1250
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001251 /* Setting limited discoverable when powered off is
1252 * not a valid operation since it requires a timeout
1253 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1254 */
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001255 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1256 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1257 changed = true;
1258 }
1259
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001260 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001261 if (err < 0)
1262 goto failed;
1263
1264 if (changed)
1265 err = new_settings(hdev, sk);
1266
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001267 goto failed;
1268 }
1269
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001270 /* If the current mode is the same, then just update the timeout
1271 * value with the new value. And if only the timeout gets updated,
1272 * then no need for any HCI transactions.
1273 */
1274 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) &&
1275 (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE,
1276 &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001277 cancel_delayed_work(&hdev->discov_off);
1278 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001279
Marcel Holtmann36261542013-10-15 08:28:51 -07001280 if (cp->val && hdev->discov_timeout > 0) {
1281 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001282 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001283 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001284 }
1285
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001286 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001287 goto failed;
1288 }
1289
1290 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1291 if (!cmd) {
1292 err = -ENOMEM;
1293 goto failed;
1294 }
1295
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001296 /* Cancel any potential discoverable timeout that might be
1297 * still active and store new timeout value. The arming of
1298 * the timeout happens in the complete handler.
1299 */
1300 cancel_delayed_work(&hdev->discov_off);
1301 hdev->discov_timeout = timeout;
1302
Johan Hedbergb456f872013-10-19 23:38:22 +03001303 /* Limited discoverable mode */
1304 if (cp->val == 0x02)
1305 set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1306 else
1307 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1308
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001309 hci_req_init(&req, hdev);
1310
Johan Hedberg9a43e252013-10-20 19:00:07 +03001311 /* The procedure for LE-only controllers is much simpler - just
1312 * update the advertising data.
1313 */
1314 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1315 goto update_ad;
1316
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001317 scan = SCAN_PAGE;
1318
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001319 if (cp->val) {
1320 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001321
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001322 if (cp->val == 0x02) {
1323 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001324 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001325 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1326 hci_cp.iac_lap[1] = 0x8b;
1327 hci_cp.iac_lap[2] = 0x9e;
1328 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1329 hci_cp.iac_lap[4] = 0x8b;
1330 hci_cp.iac_lap[5] = 0x9e;
1331 } else {
1332 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001333 hci_cp.num_iac = 1;
1334 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1335 hci_cp.iac_lap[1] = 0x8b;
1336 hci_cp.iac_lap[2] = 0x9e;
1337 }
1338
1339 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1340 (hci_cp.num_iac * 3) + 1, &hci_cp);
1341
1342 scan |= SCAN_INQUIRY;
1343 } else {
1344 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1345 }
1346
1347 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001348
Johan Hedberg9a43e252013-10-20 19:00:07 +03001349update_ad:
1350 update_adv_data(&req);
1351
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001352 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001353 if (err < 0)
1354 mgmt_pending_remove(cmd);
1355
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001356failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001357 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001358 return err;
1359}
1360
Johan Hedberg406d7802013-03-15 17:07:09 -05001361static void write_fast_connectable(struct hci_request *req, bool enable)
1362{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001363 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001364 struct hci_cp_write_page_scan_activity acp;
1365 u8 type;
1366
Johan Hedberg547003b2013-10-21 16:51:53 +03001367 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1368 return;
1369
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001370 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1371 return;
1372
Johan Hedberg406d7802013-03-15 17:07:09 -05001373 if (enable) {
1374 type = PAGE_SCAN_TYPE_INTERLACED;
1375
1376 /* 160 msec page scan interval */
1377 acp.interval = __constant_cpu_to_le16(0x0100);
1378 } else {
1379 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1380
1381 /* default 1.28 sec page scan */
1382 acp.interval = __constant_cpu_to_le16(0x0800);
1383 }
1384
1385 acp.window = __constant_cpu_to_le16(0x0012);
1386
Johan Hedbergbd98b992013-03-15 17:07:13 -05001387 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1388 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1389 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1390 sizeof(acp), &acp);
1391
1392 if (hdev->page_scan_type != type)
1393 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001394}
1395
Johan Hedberg2b76f452013-03-15 17:07:04 -05001396static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1397{
1398 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001399 struct mgmt_mode *cp;
1400 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001401
1402 BT_DBG("status 0x%02x", status);
1403
1404 hci_dev_lock(hdev);
1405
1406 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1407 if (!cmd)
1408 goto unlock;
1409
Johan Hedberg37438c12013-10-14 16:20:05 +03001410 if (status) {
1411 u8 mgmt_err = mgmt_status(status);
1412 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1413 goto remove_cmd;
1414 }
1415
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001416 cp = cmd->param;
1417 if (cp->val)
1418 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1419 else
1420 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1421
Johan Hedberg2b76f452013-03-15 17:07:04 -05001422 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1423
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001424 if (changed)
1425 new_settings(hdev, cmd->sk);
1426
Johan Hedberg37438c12013-10-14 16:20:05 +03001427remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001428 mgmt_pending_remove(cmd);
1429
1430unlock:
1431 hci_dev_unlock(hdev);
1432}
1433
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001434static int set_connectable_update_settings(struct hci_dev *hdev,
1435 struct sock *sk, u8 val)
1436{
1437 bool changed = false;
1438 int err;
1439
1440 if (!!val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1441 changed = true;
1442
1443 if (val) {
1444 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1445 } else {
1446 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1447 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1448 }
1449
1450 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1451 if (err < 0)
1452 return err;
1453
1454 if (changed)
1455 return new_settings(hdev, sk);
1456
1457 return 0;
1458}
1459
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001460static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001461 u16 len)
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001462{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001463 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001464 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001465 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001466 u8 scan;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001467 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001468
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001469 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001470
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001471 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1472 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001473 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001474 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001475
Johan Hedberga7e80f22013-01-09 16:05:19 +02001476 if (cp->val != 0x00 && cp->val != 0x01)
1477 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1478 MGMT_STATUS_INVALID_PARAMS);
1479
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001480 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001481
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001482 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001483 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001484 goto failed;
1485 }
1486
1487 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001488 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001489 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001490 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001491 goto failed;
1492 }
1493
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001494 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1495 if (!cmd) {
1496 err = -ENOMEM;
1497 goto failed;
1498 }
1499
Johan Hedberg2b76f452013-03-15 17:07:04 -05001500 hci_req_init(&req, hdev);
1501
Johan Hedberg9a43e252013-10-20 19:00:07 +03001502 /* If BR/EDR is not enabled and we disable advertising as a
1503 * by-product of disabling connectable, we need to update the
1504 * advertising flags.
1505 */
1506 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
1507 if (!cp->val) {
1508 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1509 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1510 }
1511 update_adv_data(&req);
1512 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001513 if (cp->val) {
1514 scan = SCAN_PAGE;
1515 } else {
1516 scan = 0;
1517
1518 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001519 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001520 cancel_delayed_work(&hdev->discov_off);
1521 }
1522
1523 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1524 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001525
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001526 /* If we're going from non-connectable to connectable or
1527 * vice-versa when fast connectable is enabled ensure that fast
1528 * connectable gets disabled. write_fast_connectable won't do
1529 * anything if the page scan parameters are already what they
1530 * should be.
1531 */
1532 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001533 write_fast_connectable(&req, false);
1534
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001535 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1536 hci_conn_num(hdev, LE_LINK) == 0) {
1537 disable_advertising(&req);
1538 enable_advertising(&req);
1539 }
1540
Johan Hedberg2b76f452013-03-15 17:07:04 -05001541 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001542 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001543 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001544 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03001545 err = set_connectable_update_settings(hdev, sk,
1546 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03001547 goto failed;
1548 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001549
1550failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001551 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001552 return err;
1553}
1554
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001555static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001556 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001557{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001558 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001559 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001560 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001561
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001562 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001563
Johan Hedberga7e80f22013-01-09 16:05:19 +02001564 if (cp->val != 0x00 && cp->val != 0x01)
1565 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1566 MGMT_STATUS_INVALID_PARAMS);
1567
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001568 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001569
1570 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001571 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001572 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001573 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001574
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001575 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001576 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001577 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001578
Marcel Holtmann55594352013-10-06 16:11:57 -07001579 if (changed)
1580 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001581
Marcel Holtmann55594352013-10-06 16:11:57 -07001582unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001583 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001584 return err;
1585}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001586
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001587static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1588 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001589{
1590 struct mgmt_mode *cp = data;
1591 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001592 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001593 int err;
1594
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001595 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001596
Johan Hedberge6fe7982013-10-02 15:45:22 +03001597 status = mgmt_bredr_support(hdev);
1598 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001599 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001600 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001601
Johan Hedberga7e80f22013-01-09 16:05:19 +02001602 if (cp->val != 0x00 && cp->val != 0x01)
1603 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1604 MGMT_STATUS_INVALID_PARAMS);
1605
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001606 hci_dev_lock(hdev);
1607
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001608 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001609 bool changed = false;
1610
1611 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001612 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001613 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1614 changed = true;
1615 }
1616
1617 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1618 if (err < 0)
1619 goto failed;
1620
1621 if (changed)
1622 err = new_settings(hdev, sk);
1623
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001624 goto failed;
1625 }
1626
1627 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001628 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001629 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001630 goto failed;
1631 }
1632
1633 val = !!cp->val;
1634
1635 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1636 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1637 goto failed;
1638 }
1639
1640 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1641 if (!cmd) {
1642 err = -ENOMEM;
1643 goto failed;
1644 }
1645
1646 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1647 if (err < 0) {
1648 mgmt_pending_remove(cmd);
1649 goto failed;
1650 }
1651
1652failed:
1653 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001654 return err;
1655}
1656
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001657static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001658{
1659 struct mgmt_mode *cp = data;
1660 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001661 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001662 int err;
1663
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001664 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001665
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001666 status = mgmt_bredr_support(hdev);
1667 if (status)
1668 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1669
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001670 if (!lmp_ssp_capable(hdev))
1671 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1672 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001673
Johan Hedberga7e80f22013-01-09 16:05:19 +02001674 if (cp->val != 0x00 && cp->val != 0x01)
1675 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1676 MGMT_STATUS_INVALID_PARAMS);
1677
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001678 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001679
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001680 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001681 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001682
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001683 if (cp->val) {
1684 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1685 &hdev->dev_flags);
1686 } else {
1687 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1688 &hdev->dev_flags);
1689 if (!changed)
1690 changed = test_and_clear_bit(HCI_HS_ENABLED,
1691 &hdev->dev_flags);
1692 else
1693 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001694 }
1695
1696 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1697 if (err < 0)
1698 goto failed;
1699
1700 if (changed)
1701 err = new_settings(hdev, sk);
1702
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001703 goto failed;
1704 }
1705
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001706 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1707 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001708 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1709 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001710 goto failed;
1711 }
1712
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001713 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001714 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1715 goto failed;
1716 }
1717
1718 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1719 if (!cmd) {
1720 err = -ENOMEM;
1721 goto failed;
1722 }
1723
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001724 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001725 if (err < 0) {
1726 mgmt_pending_remove(cmd);
1727 goto failed;
1728 }
1729
1730failed:
1731 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001732 return err;
1733}
1734
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001735static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001736{
1737 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001738 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001739 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001740 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001741
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001742 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001743
Johan Hedberge6fe7982013-10-02 15:45:22 +03001744 status = mgmt_bredr_support(hdev);
1745 if (status)
1746 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001747
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001748 if (!lmp_ssp_capable(hdev))
1749 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1750 MGMT_STATUS_NOT_SUPPORTED);
1751
1752 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1753 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1754 MGMT_STATUS_REJECTED);
1755
Johan Hedberga7e80f22013-01-09 16:05:19 +02001756 if (cp->val != 0x00 && cp->val != 0x01)
1757 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1758 MGMT_STATUS_INVALID_PARAMS);
1759
Marcel Holtmannee392692013-10-01 22:59:23 -07001760 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001761
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001762 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001763 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001764 } else {
1765 if (hdev_is_powered(hdev)) {
1766 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1767 MGMT_STATUS_REJECTED);
1768 goto unlock;
1769 }
1770
Marcel Holtmannee392692013-10-01 22:59:23 -07001771 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001772 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001773
1774 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1775 if (err < 0)
1776 goto unlock;
1777
1778 if (changed)
1779 err = new_settings(hdev, sk);
1780
1781unlock:
1782 hci_dev_unlock(hdev);
1783 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001784}
1785
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001786static void le_enable_complete(struct hci_dev *hdev, u8 status)
1787{
1788 struct cmd_lookup match = { NULL, hdev };
1789
1790 if (status) {
1791 u8 mgmt_err = mgmt_status(status);
1792
1793 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1794 &mgmt_err);
1795 return;
1796 }
1797
1798 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1799
1800 new_settings(hdev, match.sk);
1801
1802 if (match.sk)
1803 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001804
1805 /* Make sure the controller has a good default for
1806 * advertising data. Restrict the update to when LE
1807 * has actually been enabled. During power on, the
1808 * update in powered_update_hci will take care of it.
1809 */
1810 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1811 struct hci_request req;
1812
1813 hci_dev_lock(hdev);
1814
1815 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001816 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07001817 update_scan_rsp_data(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001818 hci_req_run(&req, NULL);
1819
1820 hci_dev_unlock(hdev);
1821 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001822}
1823
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001824static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001825{
1826 struct mgmt_mode *cp = data;
1827 struct hci_cp_write_le_host_supported hci_cp;
1828 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001829 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001830 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001831 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001832
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001833 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001834
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001835 if (!lmp_le_capable(hdev))
1836 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1837 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001838
Johan Hedberga7e80f22013-01-09 16:05:19 +02001839 if (cp->val != 0x00 && cp->val != 0x01)
1840 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1841 MGMT_STATUS_INVALID_PARAMS);
1842
Johan Hedbergc73eee92013-04-19 18:35:21 +03001843 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001844 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001845 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1846 MGMT_STATUS_REJECTED);
1847
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001848 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001849
1850 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001851 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001852
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001853 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001854 bool changed = false;
1855
1856 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1857 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1858 changed = true;
1859 }
1860
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001861 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1862 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001863 changed = true;
1864 }
1865
Johan Hedberg06199cf2012-02-22 16:37:11 +02001866 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1867 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001868 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001869
1870 if (changed)
1871 err = new_settings(hdev, sk);
1872
Johan Hedberg1de028c2012-02-29 19:55:35 -08001873 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001874 }
1875
Johan Hedberg4375f102013-09-25 13:26:10 +03001876 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1877 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001878 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001879 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001880 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001881 }
1882
1883 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1884 if (!cmd) {
1885 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001886 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001887 }
1888
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001889 hci_req_init(&req, hdev);
1890
Johan Hedberg06199cf2012-02-22 16:37:11 +02001891 memset(&hci_cp, 0, sizeof(hci_cp));
1892
1893 if (val) {
1894 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001895 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001896 } else {
1897 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1898 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001899 }
1900
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001901 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1902 &hci_cp);
1903
1904 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301905 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001906 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001907
Johan Hedberg1de028c2012-02-29 19:55:35 -08001908unlock:
1909 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001910 return err;
1911}
1912
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001913/* This is a helper function to test for pending mgmt commands that can
1914 * cause CoD or EIR HCI commands. We can only allow one such pending
1915 * mgmt command at a time since otherwise we cannot easily track what
1916 * the current values are, will be, and based on that calculate if a new
1917 * HCI command needs to be sent and if yes with what value.
1918 */
1919static bool pending_eir_or_class(struct hci_dev *hdev)
1920{
1921 struct pending_cmd *cmd;
1922
1923 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1924 switch (cmd->opcode) {
1925 case MGMT_OP_ADD_UUID:
1926 case MGMT_OP_REMOVE_UUID:
1927 case MGMT_OP_SET_DEV_CLASS:
1928 case MGMT_OP_SET_POWERED:
1929 return true;
1930 }
1931 }
1932
1933 return false;
1934}
1935
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001936static const u8 bluetooth_base_uuid[] = {
1937 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1938 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1939};
1940
1941static u8 get_uuid_size(const u8 *uuid)
1942{
1943 u32 val;
1944
1945 if (memcmp(uuid, bluetooth_base_uuid, 12))
1946 return 128;
1947
1948 val = get_unaligned_le32(&uuid[12]);
1949 if (val > 0xffff)
1950 return 32;
1951
1952 return 16;
1953}
1954
Johan Hedberg92da6092013-03-15 17:06:55 -05001955static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1956{
1957 struct pending_cmd *cmd;
1958
1959 hci_dev_lock(hdev);
1960
1961 cmd = mgmt_pending_find(mgmt_op, hdev);
1962 if (!cmd)
1963 goto unlock;
1964
1965 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1966 hdev->dev_class, 3);
1967
1968 mgmt_pending_remove(cmd);
1969
1970unlock:
1971 hci_dev_unlock(hdev);
1972}
1973
1974static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1975{
1976 BT_DBG("status 0x%02x", status);
1977
1978 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1979}
1980
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001981static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001982{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001983 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001984 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001985 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001986 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001987 int err;
1988
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001989 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001990
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001991 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001992
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001993 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001994 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001995 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001996 goto failed;
1997 }
1998
Andre Guedes92c4c202012-06-07 19:05:44 -03001999 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002000 if (!uuid) {
2001 err = -ENOMEM;
2002 goto failed;
2003 }
2004
2005 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002006 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002007 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002008
Johan Hedbergde66aa62013-01-27 00:31:27 +02002009 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002010
Johan Hedberg890ea892013-03-15 17:06:52 -05002011 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002012
Johan Hedberg890ea892013-03-15 17:06:52 -05002013 update_class(&req);
2014 update_eir(&req);
2015
Johan Hedberg92da6092013-03-15 17:06:55 -05002016 err = hci_req_run(&req, add_uuid_complete);
2017 if (err < 0) {
2018 if (err != -ENODATA)
2019 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002020
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002021 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002022 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002023 goto failed;
2024 }
2025
2026 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002027 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002028 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002029 goto failed;
2030 }
2031
2032 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002033
2034failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002035 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002036 return err;
2037}
2038
Johan Hedberg24b78d02012-02-23 23:24:30 +02002039static bool enable_service_cache(struct hci_dev *hdev)
2040{
2041 if (!hdev_is_powered(hdev))
2042 return false;
2043
2044 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002045 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2046 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002047 return true;
2048 }
2049
2050 return false;
2051}
2052
Johan Hedberg92da6092013-03-15 17:06:55 -05002053static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
2054{
2055 BT_DBG("status 0x%02x", status);
2056
2057 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2058}
2059
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002060static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002061 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002062{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002063 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002064 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002065 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002066 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 -05002067 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002068 int err, found;
2069
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002070 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002071
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002072 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002073
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002074 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002075 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002076 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002077 goto unlock;
2078 }
2079
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002080 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002081 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002082
Johan Hedberg24b78d02012-02-23 23:24:30 +02002083 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002084 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002085 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002086 goto unlock;
2087 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002088
Johan Hedberg9246a862012-02-23 21:33:16 +02002089 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002090 }
2091
2092 found = 0;
2093
Johan Hedberg056341c2013-01-27 00:31:30 +02002094 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002095 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2096 continue;
2097
2098 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002099 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002100 found++;
2101 }
2102
2103 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002104 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002105 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002106 goto unlock;
2107 }
2108
Johan Hedberg9246a862012-02-23 21:33:16 +02002109update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002110 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002111
Johan Hedberg890ea892013-03-15 17:06:52 -05002112 update_class(&req);
2113 update_eir(&req);
2114
Johan Hedberg92da6092013-03-15 17:06:55 -05002115 err = hci_req_run(&req, remove_uuid_complete);
2116 if (err < 0) {
2117 if (err != -ENODATA)
2118 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002119
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002120 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002121 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002122 goto unlock;
2123 }
2124
2125 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002126 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002127 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002128 goto unlock;
2129 }
2130
2131 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002132
2133unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002134 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002135 return err;
2136}
2137
Johan Hedberg92da6092013-03-15 17:06:55 -05002138static void set_class_complete(struct hci_dev *hdev, u8 status)
2139{
2140 BT_DBG("status 0x%02x", status);
2141
2142 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2143}
2144
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002145static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002146 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002147{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002148 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002149 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002150 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002151 int err;
2152
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002153 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002154
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002155 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002156 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2157 MGMT_STATUS_NOT_SUPPORTED);
2158
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002159 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002160
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002161 if (pending_eir_or_class(hdev)) {
2162 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2163 MGMT_STATUS_BUSY);
2164 goto unlock;
2165 }
2166
2167 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2168 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2169 MGMT_STATUS_INVALID_PARAMS);
2170 goto unlock;
2171 }
2172
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002173 hdev->major_class = cp->major;
2174 hdev->minor_class = cp->minor;
2175
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002176 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002177 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002178 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002179 goto unlock;
2180 }
2181
Johan Hedberg890ea892013-03-15 17:06:52 -05002182 hci_req_init(&req, hdev);
2183
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002184 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002185 hci_dev_unlock(hdev);
2186 cancel_delayed_work_sync(&hdev->service_cache);
2187 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002188 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002189 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002190
Johan Hedberg890ea892013-03-15 17:06:52 -05002191 update_class(&req);
2192
Johan Hedberg92da6092013-03-15 17:06:55 -05002193 err = hci_req_run(&req, set_class_complete);
2194 if (err < 0) {
2195 if (err != -ENODATA)
2196 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002197
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002198 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002199 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002200 goto unlock;
2201 }
2202
2203 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002204 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002205 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002206 goto unlock;
2207 }
2208
2209 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002210
Johan Hedbergb5235a62012-02-21 14:32:24 +02002211unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002212 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002213 return err;
2214}
2215
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002216static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002217 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002218{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002219 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002220 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002221 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002222 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002223
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002224 BT_DBG("request for %s", hdev->name);
2225
2226 if (!lmp_bredr_capable(hdev))
2227 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2228 MGMT_STATUS_NOT_SUPPORTED);
2229
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002230 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002231
Johan Hedberg86742e12011-11-07 23:13:38 +02002232 expected_len = sizeof(*cp) + key_count *
2233 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002234 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002235 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002236 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002237 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002238 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002239 }
2240
Johan Hedberg4ae14302013-01-20 14:27:13 +02002241 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2242 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2243 MGMT_STATUS_INVALID_PARAMS);
2244
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002245 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002246 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002247
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002248 for (i = 0; i < key_count; i++) {
2249 struct mgmt_link_key_info *key = &cp->keys[i];
2250
Marcel Holtmann8e991132014-01-10 02:07:25 -08002251 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002252 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2253 MGMT_STATUS_INVALID_PARAMS);
2254 }
2255
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002256 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002257
2258 hci_link_keys_clear(hdev);
2259
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002260 if (cp->debug_keys)
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002261 changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002262 else
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002263 changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
2264
2265 if (changed)
2266 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002267
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002268 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002269 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002270
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002271 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002272 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002273 }
2274
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002275 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002276
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002277 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002278
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002279 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002280}
2281
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002282static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002283 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002284{
2285 struct mgmt_ev_device_unpaired ev;
2286
2287 bacpy(&ev.addr.bdaddr, bdaddr);
2288 ev.addr.type = addr_type;
2289
2290 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002291 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002292}
2293
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002294static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002295 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002296{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002297 struct mgmt_cp_unpair_device *cp = data;
2298 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002299 struct hci_cp_disconnect dc;
2300 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002301 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002302 int err;
2303
Johan Hedberga8a1d192011-11-10 15:54:38 +02002304 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002305 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2306 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002307
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002308 if (!bdaddr_type_is_valid(cp->addr.type))
2309 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2310 MGMT_STATUS_INVALID_PARAMS,
2311 &rp, sizeof(rp));
2312
Johan Hedberg118da702013-01-20 14:27:20 +02002313 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2314 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2315 MGMT_STATUS_INVALID_PARAMS,
2316 &rp, sizeof(rp));
2317
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002318 hci_dev_lock(hdev);
2319
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002320 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002321 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002322 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002323 goto unlock;
2324 }
2325
Johan Hedberge0b2b272014-02-18 17:14:31 +02002326 if (cp->addr.type == BDADDR_BREDR) {
Johan Hedberg124f6e32012-02-09 13:50:12 +02002327 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedberge0b2b272014-02-18 17:14:31 +02002328 } else {
2329 u8 addr_type;
2330
2331 if (cp->addr.type == BDADDR_LE_PUBLIC)
2332 addr_type = ADDR_LE_DEV_PUBLIC;
2333 else
2334 addr_type = ADDR_LE_DEV_RANDOM;
2335
Johan Hedberga7ec7332014-02-18 17:14:35 +02002336 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2337
Johan Hedberge0b2b272014-02-18 17:14:31 +02002338 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
2339 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002340
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002341 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002342 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002343 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002344 goto unlock;
2345 }
2346
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002347 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002348 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002349 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002350 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002351 else
2352 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002353 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002354 } else {
2355 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002356 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002357
Johan Hedberga8a1d192011-11-10 15:54:38 +02002358 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002359 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002360 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002361 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002362 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002363 }
2364
Johan Hedberg124f6e32012-02-09 13:50:12 +02002365 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002366 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002367 if (!cmd) {
2368 err = -ENOMEM;
2369 goto unlock;
2370 }
2371
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002372 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002373 dc.reason = 0x13; /* Remote User Terminated Connection */
2374 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2375 if (err < 0)
2376 mgmt_pending_remove(cmd);
2377
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002378unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002379 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002380 return err;
2381}
2382
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002383static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002384 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002385{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002386 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002387 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002388 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002389 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002390 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002391 int err;
2392
2393 BT_DBG("");
2394
Johan Hedberg06a63b12013-01-20 14:27:21 +02002395 memset(&rp, 0, sizeof(rp));
2396 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2397 rp.addr.type = cp->addr.type;
2398
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002399 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002400 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2401 MGMT_STATUS_INVALID_PARAMS,
2402 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002403
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002404 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002405
2406 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002407 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2408 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002409 goto failed;
2410 }
2411
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002412 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002413 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2414 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002415 goto failed;
2416 }
2417
Andre Guedes591f47f2012-04-24 21:02:49 -03002418 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002419 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2420 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002421 else
2422 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002423
Vishal Agarwalf9607272012-06-13 05:32:43 +05302424 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002425 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2426 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002427 goto failed;
2428 }
2429
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002430 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002431 if (!cmd) {
2432 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002433 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002434 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002435
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002436 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002437 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002438
2439 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2440 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002441 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002442
2443failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002444 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002445 return err;
2446}
2447
Andre Guedes57c14772012-04-24 21:02:50 -03002448static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002449{
2450 switch (link_type) {
2451 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002452 switch (addr_type) {
2453 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002454 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002455
Johan Hedberg48264f02011-11-09 13:58:58 +02002456 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002457 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002458 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002459 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002460
Johan Hedberg4c659c32011-11-07 23:13:39 +02002461 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002462 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002463 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002464 }
2465}
2466
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002467static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2468 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002469{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002470 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002471 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002472 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002473 int err;
2474 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002475
2476 BT_DBG("");
2477
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002478 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002479
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002480 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002481 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002482 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002483 goto unlock;
2484 }
2485
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002486 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002487 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2488 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002489 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002490 }
2491
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002492 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002493 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002494 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002495 err = -ENOMEM;
2496 goto unlock;
2497 }
2498
Johan Hedberg2784eb42011-01-21 13:56:35 +02002499 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002500 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002501 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2502 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002503 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002504 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002505 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002506 continue;
2507 i++;
2508 }
2509
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002510 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002511
Johan Hedberg4c659c32011-11-07 23:13:39 +02002512 /* Recalculate length in case of filtered SCO connections, etc */
2513 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002514
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002515 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002516 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002517
Johan Hedberga38528f2011-01-22 06:46:43 +02002518 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002519
2520unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002521 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002522 return err;
2523}
2524
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002525static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002526 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002527{
2528 struct pending_cmd *cmd;
2529 int err;
2530
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002531 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002532 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002533 if (!cmd)
2534 return -ENOMEM;
2535
Johan Hedbergd8457692012-02-17 14:24:57 +02002536 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002537 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002538 if (err < 0)
2539 mgmt_pending_remove(cmd);
2540
2541 return err;
2542}
2543
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002544static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002545 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002546{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002547 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002548 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002549 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002550 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002551 int err;
2552
2553 BT_DBG("");
2554
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002555 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002556
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002557 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002558 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002559 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002560 goto failed;
2561 }
2562
Johan Hedbergd8457692012-02-17 14:24:57 +02002563 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002564 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002565 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002566 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002567 goto failed;
2568 }
2569
2570 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002571 struct mgmt_cp_pin_code_neg_reply ncp;
2572
2573 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002574
2575 BT_ERR("PIN code is not 16 bytes long");
2576
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002577 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002578 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002579 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002580 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002581
2582 goto failed;
2583 }
2584
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002585 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002586 if (!cmd) {
2587 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002588 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002589 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002590
Johan Hedbergd8457692012-02-17 14:24:57 +02002591 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002592 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002593 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002594
2595 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2596 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002597 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002598
2599failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002600 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002601 return err;
2602}
2603
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002604static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2605 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002606{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002607 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002608
2609 BT_DBG("");
2610
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002611 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002612
2613 hdev->io_capability = cp->io_capability;
2614
2615 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002616 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002617
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002618 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002619
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002620 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2621 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002622}
2623
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002624static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002625{
2626 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002627 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002628
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002629 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002630 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2631 continue;
2632
Johan Hedberge9a416b2011-02-19 12:05:56 -03002633 if (cmd->user_data != conn)
2634 continue;
2635
2636 return cmd;
2637 }
2638
2639 return NULL;
2640}
2641
2642static void pairing_complete(struct pending_cmd *cmd, u8 status)
2643{
2644 struct mgmt_rp_pair_device rp;
2645 struct hci_conn *conn = cmd->user_data;
2646
Johan Hedbergba4e5642011-11-11 00:07:34 +02002647 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002648 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002649
Johan Hedbergaee9b212012-02-18 15:07:59 +02002650 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002651 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002652
2653 /* So we don't get further callbacks for this connection */
2654 conn->connect_cfm_cb = NULL;
2655 conn->security_cfm_cb = NULL;
2656 conn->disconn_cfm_cb = NULL;
2657
David Herrmann76a68ba2013-04-06 20:28:37 +02002658 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002659
Johan Hedberga664b5b2011-02-19 12:06:02 -03002660 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002661}
2662
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002663void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2664{
2665 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
2666 struct pending_cmd *cmd;
2667
2668 cmd = find_pairing(conn);
2669 if (cmd)
2670 pairing_complete(cmd, status);
2671}
2672
Johan Hedberge9a416b2011-02-19 12:05:56 -03002673static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2674{
2675 struct pending_cmd *cmd;
2676
2677 BT_DBG("status %u", status);
2678
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002679 cmd = find_pairing(conn);
2680 if (!cmd)
2681 BT_DBG("Unable to find a pending command");
2682 else
Johan Hedberge2113262012-02-18 15:20:03 +02002683 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002684}
2685
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002686static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302687{
2688 struct pending_cmd *cmd;
2689
2690 BT_DBG("status %u", status);
2691
2692 if (!status)
2693 return;
2694
2695 cmd = find_pairing(conn);
2696 if (!cmd)
2697 BT_DBG("Unable to find a pending command");
2698 else
2699 pairing_complete(cmd, mgmt_status(status));
2700}
2701
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002702static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002703 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002704{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002705 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002706 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002707 struct pending_cmd *cmd;
2708 u8 sec_level, auth_type;
2709 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002710 int err;
2711
2712 BT_DBG("");
2713
Szymon Jancf950a30e2013-01-18 12:48:07 +01002714 memset(&rp, 0, sizeof(rp));
2715 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2716 rp.addr.type = cp->addr.type;
2717
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002718 if (!bdaddr_type_is_valid(cp->addr.type))
2719 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2720 MGMT_STATUS_INVALID_PARAMS,
2721 &rp, sizeof(rp));
2722
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002723 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002724
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002725 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002726 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2727 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002728 goto unlock;
2729 }
2730
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002731 sec_level = BT_SECURITY_MEDIUM;
2732 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002733 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002734 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002735 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002736
Andre Guedes591f47f2012-04-24 21:02:49 -03002737 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002738 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2739 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002740 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002741 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2742 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002743
Ville Tervo30e76272011-02-22 16:10:53 -03002744 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002745 int status;
2746
2747 if (PTR_ERR(conn) == -EBUSY)
2748 status = MGMT_STATUS_BUSY;
2749 else
2750 status = MGMT_STATUS_CONNECT_FAILED;
2751
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002752 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002753 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002754 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002755 goto unlock;
2756 }
2757
2758 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002759 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002760 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002761 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002762 goto unlock;
2763 }
2764
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002765 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002766 if (!cmd) {
2767 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002768 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002769 goto unlock;
2770 }
2771
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002772 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002773 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002774 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002775 conn->security_cfm_cb = pairing_complete_cb;
2776 conn->disconn_cfm_cb = pairing_complete_cb;
2777 } else {
2778 conn->connect_cfm_cb = le_pairing_complete_cb;
2779 conn->security_cfm_cb = le_pairing_complete_cb;
2780 conn->disconn_cfm_cb = le_pairing_complete_cb;
2781 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002782
Johan Hedberge9a416b2011-02-19 12:05:56 -03002783 conn->io_capability = cp->io_cap;
2784 cmd->user_data = conn;
2785
2786 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002787 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002788 pairing_complete(cmd, 0);
2789
2790 err = 0;
2791
2792unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002793 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002794 return err;
2795}
2796
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002797static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2798 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002799{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002800 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002801 struct pending_cmd *cmd;
2802 struct hci_conn *conn;
2803 int err;
2804
2805 BT_DBG("");
2806
Johan Hedberg28424702012-02-02 04:02:29 +02002807 hci_dev_lock(hdev);
2808
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002809 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002810 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002811 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002812 goto unlock;
2813 }
2814
Johan Hedberg28424702012-02-02 04:02:29 +02002815 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2816 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002817 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002818 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002819 goto unlock;
2820 }
2821
2822 conn = cmd->user_data;
2823
2824 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002825 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002826 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002827 goto unlock;
2828 }
2829
2830 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2831
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002832 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002833 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002834unlock:
2835 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002836 return err;
2837}
2838
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002839static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002840 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002841 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002842{
Johan Hedberga5c29682011-02-19 12:05:57 -03002843 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002844 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002845 int err;
2846
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002847 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002848
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002849 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002850 err = cmd_complete(sk, hdev->id, mgmt_op,
2851 MGMT_STATUS_NOT_POWERED, addr,
2852 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002853 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002854 }
2855
Johan Hedberg1707c602013-03-15 17:07:15 -05002856 if (addr->type == BDADDR_BREDR)
2857 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002858 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002859 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002860
Johan Hedberg272d90d2012-02-09 15:26:12 +02002861 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002862 err = cmd_complete(sk, hdev->id, mgmt_op,
2863 MGMT_STATUS_NOT_CONNECTED, addr,
2864 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002865 goto done;
2866 }
2867
Johan Hedberg1707c602013-03-15 17:07:15 -05002868 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002869 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002870 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002871
Brian Gix5fe57d92011-12-21 16:12:13 -08002872 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002873 err = cmd_complete(sk, hdev->id, mgmt_op,
2874 MGMT_STATUS_SUCCESS, addr,
2875 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002876 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002877 err = cmd_complete(sk, hdev->id, mgmt_op,
2878 MGMT_STATUS_FAILED, addr,
2879 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002880
Brian Gix47c15e22011-11-16 13:53:14 -08002881 goto done;
2882 }
2883
Johan Hedberg1707c602013-03-15 17:07:15 -05002884 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002885 if (!cmd) {
2886 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002887 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002888 }
2889
Brian Gix0df4c182011-11-16 13:53:13 -08002890 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002891 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2892 struct hci_cp_user_passkey_reply cp;
2893
Johan Hedberg1707c602013-03-15 17:07:15 -05002894 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002895 cp.passkey = passkey;
2896 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2897 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002898 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2899 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002900
Johan Hedberga664b5b2011-02-19 12:06:02 -03002901 if (err < 0)
2902 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002903
Brian Gix0df4c182011-11-16 13:53:13 -08002904done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002905 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002906 return err;
2907}
2908
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302909static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2910 void *data, u16 len)
2911{
2912 struct mgmt_cp_pin_code_neg_reply *cp = data;
2913
2914 BT_DBG("");
2915
Johan Hedberg1707c602013-03-15 17:07:15 -05002916 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302917 MGMT_OP_PIN_CODE_NEG_REPLY,
2918 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2919}
2920
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002921static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2922 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002923{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002924 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002925
2926 BT_DBG("");
2927
2928 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002929 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002930 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002931
Johan Hedberg1707c602013-03-15 17:07:15 -05002932 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002933 MGMT_OP_USER_CONFIRM_REPLY,
2934 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002935}
2936
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002937static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002938 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002939{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002940 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002941
2942 BT_DBG("");
2943
Johan Hedberg1707c602013-03-15 17:07:15 -05002944 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002945 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2946 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002947}
2948
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002949static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2950 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002951{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002952 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002953
2954 BT_DBG("");
2955
Johan Hedberg1707c602013-03-15 17:07:15 -05002956 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002957 MGMT_OP_USER_PASSKEY_REPLY,
2958 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002959}
2960
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002961static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002962 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002963{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002964 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002965
2966 BT_DBG("");
2967
Johan Hedberg1707c602013-03-15 17:07:15 -05002968 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002969 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2970 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002971}
2972
Johan Hedberg13928972013-03-15 17:07:00 -05002973static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002974{
Johan Hedberg13928972013-03-15 17:07:00 -05002975 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002976 struct hci_cp_write_local_name cp;
2977
Johan Hedberg13928972013-03-15 17:07:00 -05002978 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002979
Johan Hedberg890ea892013-03-15 17:06:52 -05002980 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002981}
2982
Johan Hedberg13928972013-03-15 17:07:00 -05002983static void set_name_complete(struct hci_dev *hdev, u8 status)
2984{
2985 struct mgmt_cp_set_local_name *cp;
2986 struct pending_cmd *cmd;
2987
2988 BT_DBG("status 0x%02x", status);
2989
2990 hci_dev_lock(hdev);
2991
2992 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2993 if (!cmd)
2994 goto unlock;
2995
2996 cp = cmd->param;
2997
2998 if (status)
2999 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3000 mgmt_status(status));
3001 else
3002 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3003 cp, sizeof(*cp));
3004
3005 mgmt_pending_remove(cmd);
3006
3007unlock:
3008 hci_dev_unlock(hdev);
3009}
3010
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003011static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003012 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003013{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003014 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003015 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003016 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003017 int err;
3018
3019 BT_DBG("");
3020
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003021 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003022
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003023 /* If the old values are the same as the new ones just return a
3024 * direct command complete event.
3025 */
3026 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3027 !memcmp(hdev->short_name, cp->short_name,
3028 sizeof(hdev->short_name))) {
3029 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3030 data, len);
3031 goto failed;
3032 }
3033
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003034 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003035
Johan Hedbergb5235a62012-02-21 14:32:24 +02003036 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003037 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003038
3039 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003040 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003041 if (err < 0)
3042 goto failed;
3043
3044 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003045 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003046
Johan Hedbergb5235a62012-02-21 14:32:24 +02003047 goto failed;
3048 }
3049
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003050 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003051 if (!cmd) {
3052 err = -ENOMEM;
3053 goto failed;
3054 }
3055
Johan Hedberg13928972013-03-15 17:07:00 -05003056 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3057
Johan Hedberg890ea892013-03-15 17:06:52 -05003058 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003059
3060 if (lmp_bredr_capable(hdev)) {
3061 update_name(&req);
3062 update_eir(&req);
3063 }
3064
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003065 /* The name is stored in the scan response data and so
3066 * no need to udpate the advertising data here.
3067 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003068 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003069 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003070
Johan Hedberg13928972013-03-15 17:07:00 -05003071 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003072 if (err < 0)
3073 mgmt_pending_remove(cmd);
3074
3075failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003076 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003077 return err;
3078}
3079
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003080static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003081 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003082{
Szymon Jancc35938b2011-03-22 13:12:21 +01003083 struct pending_cmd *cmd;
3084 int err;
3085
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003086 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003087
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003088 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003089
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003090 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003091 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003092 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003093 goto unlock;
3094 }
3095
Andre Guedes9a1a1992012-07-24 15:03:48 -03003096 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003097 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003098 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003099 goto unlock;
3100 }
3101
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003102 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003103 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003104 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003105 goto unlock;
3106 }
3107
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003108 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003109 if (!cmd) {
3110 err = -ENOMEM;
3111 goto unlock;
3112 }
3113
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003114 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
3115 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
3116 0, NULL);
3117 else
3118 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3119
Szymon Jancc35938b2011-03-22 13:12:21 +01003120 if (err < 0)
3121 mgmt_pending_remove(cmd);
3122
3123unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003124 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003125 return err;
3126}
3127
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003128static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003129 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003130{
Szymon Janc2763eda2011-03-22 13:12:22 +01003131 int err;
3132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003133 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003134
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003135 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003136
Marcel Holtmannec109112014-01-10 02:07:30 -08003137 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3138 struct mgmt_cp_add_remote_oob_data *cp = data;
3139 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003140
Marcel Holtmannec109112014-01-10 02:07:30 -08003141 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
3142 cp->hash, cp->randomizer);
3143 if (err < 0)
3144 status = MGMT_STATUS_FAILED;
3145 else
3146 status = MGMT_STATUS_SUCCESS;
3147
3148 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3149 status, &cp->addr, sizeof(cp->addr));
3150 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3151 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
3152 u8 status;
3153
3154 err = hci_add_remote_oob_ext_data(hdev, &cp->addr.bdaddr,
3155 cp->hash192,
3156 cp->randomizer192,
3157 cp->hash256,
3158 cp->randomizer256);
3159 if (err < 0)
3160 status = MGMT_STATUS_FAILED;
3161 else
3162 status = MGMT_STATUS_SUCCESS;
3163
3164 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3165 status, &cp->addr, sizeof(cp->addr));
3166 } else {
3167 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
3168 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3169 MGMT_STATUS_INVALID_PARAMS);
3170 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003171
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003172 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003173 return err;
3174}
3175
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003176static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003177 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003178{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003179 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003180 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003181 int err;
3182
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003183 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003184
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003185 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003186
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003187 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003188 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003189 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003190 else
Szymon Janca6785be2012-12-13 15:11:21 +01003191 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003192
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003193 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003194 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003195
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003196 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003197 return err;
3198}
3199
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003200static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3201{
3202 struct pending_cmd *cmd;
3203 u8 type;
3204 int err;
3205
3206 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3207
3208 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3209 if (!cmd)
3210 return -ENOENT;
3211
3212 type = hdev->discovery.type;
3213
3214 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3215 &type, sizeof(type));
3216 mgmt_pending_remove(cmd);
3217
3218 return err;
3219}
3220
Andre Guedes7c307722013-04-30 15:29:28 -03003221static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3222{
3223 BT_DBG("status %d", status);
3224
3225 if (status) {
3226 hci_dev_lock(hdev);
3227 mgmt_start_discovery_failed(hdev, status);
3228 hci_dev_unlock(hdev);
3229 return;
3230 }
3231
3232 hci_dev_lock(hdev);
3233 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3234 hci_dev_unlock(hdev);
3235
3236 switch (hdev->discovery.type) {
3237 case DISCOV_TYPE_LE:
3238 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003239 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003240 break;
3241
3242 case DISCOV_TYPE_INTERLEAVED:
3243 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003244 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003245 break;
3246
3247 case DISCOV_TYPE_BREDR:
3248 break;
3249
3250 default:
3251 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3252 }
3253}
3254
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003255static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003256 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003257{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003258 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003259 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003260 struct hci_cp_le_set_scan_param param_cp;
3261 struct hci_cp_le_set_scan_enable enable_cp;
3262 struct hci_cp_inquiry inq_cp;
3263 struct hci_request req;
3264 /* General inquiry access code (GIAC) */
3265 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003266 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003267 int err;
3268
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003269 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003270
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003271 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003272
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003273 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003274 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003275 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003276 goto failed;
3277 }
3278
Andre Guedes642be6c2012-03-21 00:03:37 -03003279 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3280 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3281 MGMT_STATUS_BUSY);
3282 goto failed;
3283 }
3284
Johan Hedbergff9ef572012-01-04 14:23:45 +02003285 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003286 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003287 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003288 goto failed;
3289 }
3290
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003291 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003292 if (!cmd) {
3293 err = -ENOMEM;
3294 goto failed;
3295 }
3296
Andre Guedes4aab14e2012-02-17 20:39:36 -03003297 hdev->discovery.type = cp->type;
3298
Andre Guedes7c307722013-04-30 15:29:28 -03003299 hci_req_init(&req, hdev);
3300
Andre Guedes4aab14e2012-02-17 20:39:36 -03003301 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003302 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003303 status = mgmt_bredr_support(hdev);
3304 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003305 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003306 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003307 mgmt_pending_remove(cmd);
3308 goto failed;
3309 }
3310
Andre Guedes7c307722013-04-30 15:29:28 -03003311 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3312 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3313 MGMT_STATUS_BUSY);
3314 mgmt_pending_remove(cmd);
3315 goto failed;
3316 }
3317
3318 hci_inquiry_cache_flush(hdev);
3319
3320 memset(&inq_cp, 0, sizeof(inq_cp));
3321 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003322 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003323 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003324 break;
3325
3326 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003327 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003328 status = mgmt_le_support(hdev);
3329 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003330 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003331 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003332 mgmt_pending_remove(cmd);
3333 goto failed;
3334 }
3335
Andre Guedes7c307722013-04-30 15:29:28 -03003336 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003337 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003338 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3339 MGMT_STATUS_NOT_SUPPORTED);
3340 mgmt_pending_remove(cmd);
3341 goto failed;
3342 }
3343
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003344 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003345 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3346 MGMT_STATUS_REJECTED);
3347 mgmt_pending_remove(cmd);
3348 goto failed;
3349 }
3350
3351 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3352 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3353 MGMT_STATUS_BUSY);
3354 mgmt_pending_remove(cmd);
3355 goto failed;
3356 }
3357
3358 memset(&param_cp, 0, sizeof(param_cp));
3359 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003360 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3361 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmann79830f62013-10-18 16:38:09 -07003362 param_cp.own_address_type = hdev->own_addr_type;
Andre Guedes7c307722013-04-30 15:29:28 -03003363 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3364 &param_cp);
3365
3366 memset(&enable_cp, 0, sizeof(enable_cp));
3367 enable_cp.enable = LE_SCAN_ENABLE;
3368 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3369 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3370 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003371 break;
3372
Andre Guedesf39799f2012-02-17 20:39:35 -03003373 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003374 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3375 MGMT_STATUS_INVALID_PARAMS);
3376 mgmt_pending_remove(cmd);
3377 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003378 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003379
Andre Guedes7c307722013-04-30 15:29:28 -03003380 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003381 if (err < 0)
3382 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003383 else
3384 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003385
3386failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003387 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003388 return err;
3389}
3390
Andre Guedes1183fdc2013-04-30 15:29:35 -03003391static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3392{
3393 struct pending_cmd *cmd;
3394 int err;
3395
3396 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3397 if (!cmd)
3398 return -ENOENT;
3399
3400 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3401 &hdev->discovery.type, sizeof(hdev->discovery.type));
3402 mgmt_pending_remove(cmd);
3403
3404 return err;
3405}
3406
Andre Guedes0e05bba2013-04-30 15:29:33 -03003407static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3408{
3409 BT_DBG("status %d", status);
3410
3411 hci_dev_lock(hdev);
3412
3413 if (status) {
3414 mgmt_stop_discovery_failed(hdev, status);
3415 goto unlock;
3416 }
3417
3418 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3419
3420unlock:
3421 hci_dev_unlock(hdev);
3422}
3423
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003424static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003425 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003426{
Johan Hedbergd9306502012-02-20 23:25:18 +02003427 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003428 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003429 struct hci_cp_remote_name_req_cancel cp;
3430 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003431 struct hci_request req;
3432 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003433 int err;
3434
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003435 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003436
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003437 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003438
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003439 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003440 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003441 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3442 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003443 goto unlock;
3444 }
3445
3446 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003447 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003448 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3449 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003450 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003451 }
3452
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003453 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003454 if (!cmd) {
3455 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003456 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003457 }
3458
Andre Guedes0e05bba2013-04-30 15:29:33 -03003459 hci_req_init(&req, hdev);
3460
Andre Guedese0d9727e2012-03-20 15:15:36 -03003461 switch (hdev->discovery.state) {
3462 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003463 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3464 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3465 } else {
3466 cancel_delayed_work(&hdev->le_scan_disable);
3467
3468 memset(&enable_cp, 0, sizeof(enable_cp));
3469 enable_cp.enable = LE_SCAN_DISABLE;
3470 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3471 sizeof(enable_cp), &enable_cp);
3472 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003473
Andre Guedese0d9727e2012-03-20 15:15:36 -03003474 break;
3475
3476 case DISCOVERY_RESOLVING:
3477 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003478 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003479 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003480 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003481 err = cmd_complete(sk, hdev->id,
3482 MGMT_OP_STOP_DISCOVERY, 0,
3483 &mgmt_cp->type,
3484 sizeof(mgmt_cp->type));
3485 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3486 goto unlock;
3487 }
3488
3489 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003490 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3491 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003492
3493 break;
3494
3495 default:
3496 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003497
3498 mgmt_pending_remove(cmd);
3499 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3500 MGMT_STATUS_FAILED, &mgmt_cp->type,
3501 sizeof(mgmt_cp->type));
3502 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003503 }
3504
Andre Guedes0e05bba2013-04-30 15:29:33 -03003505 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003506 if (err < 0)
3507 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003508 else
3509 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003510
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003511unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003512 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003513 return err;
3514}
3515
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003516static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003517 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003518{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003519 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003520 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003521 int err;
3522
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003523 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003524
Johan Hedberg561aafb2012-01-04 13:31:59 +02003525 hci_dev_lock(hdev);
3526
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003527 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003528 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003529 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003530 goto failed;
3531 }
3532
Johan Hedberga198e7b2012-02-17 14:27:06 +02003533 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003534 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003535 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003536 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003537 goto failed;
3538 }
3539
3540 if (cp->name_known) {
3541 e->name_state = NAME_KNOWN;
3542 list_del(&e->list);
3543 } else {
3544 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02003545 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003546 }
3547
Johan Hedberge3846622013-01-09 15:29:33 +02003548 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3549 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003550
3551failed:
3552 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003553 return err;
3554}
3555
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003556static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003557 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003558{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003559 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003560 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003561 int err;
3562
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003563 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003564
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003565 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003566 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3567 MGMT_STATUS_INVALID_PARAMS,
3568 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003569
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003570 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003571
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003572 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003573 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003574 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003575 else
Szymon Janca6785be2012-12-13 15:11:21 +01003576 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003577
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003578 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003579 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003580
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003581 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003582
3583 return err;
3584}
3585
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003586static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003587 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003588{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003589 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003590 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003591 int err;
3592
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003593 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003594
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003595 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003596 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3597 MGMT_STATUS_INVALID_PARAMS,
3598 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003599
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003600 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003601
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003602 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003603 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003604 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003605 else
Szymon Janca6785be2012-12-13 15:11:21 +01003606 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003607
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003608 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003609 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003610
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003611 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003612
3613 return err;
3614}
3615
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003616static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3617 u16 len)
3618{
3619 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003620 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003621 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003622 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003623
3624 BT_DBG("%s", hdev->name);
3625
Szymon Jancc72d4b82012-03-16 16:02:57 +01003626 source = __le16_to_cpu(cp->source);
3627
3628 if (source > 0x0002)
3629 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3630 MGMT_STATUS_INVALID_PARAMS);
3631
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003632 hci_dev_lock(hdev);
3633
Szymon Jancc72d4b82012-03-16 16:02:57 +01003634 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003635 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3636 hdev->devid_product = __le16_to_cpu(cp->product);
3637 hdev->devid_version = __le16_to_cpu(cp->version);
3638
3639 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3640
Johan Hedberg890ea892013-03-15 17:06:52 -05003641 hci_req_init(&req, hdev);
3642 update_eir(&req);
3643 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003644
3645 hci_dev_unlock(hdev);
3646
3647 return err;
3648}
3649
Johan Hedberg4375f102013-09-25 13:26:10 +03003650static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3651{
3652 struct cmd_lookup match = { NULL, hdev };
3653
3654 if (status) {
3655 u8 mgmt_err = mgmt_status(status);
3656
3657 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3658 cmd_status_rsp, &mgmt_err);
3659 return;
3660 }
3661
3662 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3663 &match);
3664
3665 new_settings(hdev, match.sk);
3666
3667 if (match.sk)
3668 sock_put(match.sk);
3669}
3670
Marcel Holtmann21b51872013-10-10 09:47:53 -07003671static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3672 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003673{
3674 struct mgmt_mode *cp = data;
3675 struct pending_cmd *cmd;
3676 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003677 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003678 int err;
3679
3680 BT_DBG("request for %s", hdev->name);
3681
Johan Hedberge6fe7982013-10-02 15:45:22 +03003682 status = mgmt_le_support(hdev);
3683 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003684 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003685 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003686
3687 if (cp->val != 0x00 && cp->val != 0x01)
3688 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3689 MGMT_STATUS_INVALID_PARAMS);
3690
3691 hci_dev_lock(hdev);
3692
3693 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003694 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003695
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003696 /* The following conditions are ones which mean that we should
3697 * not do any HCI communication but directly send a mgmt
3698 * response to user space (after toggling the flag if
3699 * necessary).
3700 */
3701 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003702 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003703 bool changed = false;
3704
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003705 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3706 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003707 changed = true;
3708 }
3709
3710 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3711 if (err < 0)
3712 goto unlock;
3713
3714 if (changed)
3715 err = new_settings(hdev, sk);
3716
3717 goto unlock;
3718 }
3719
3720 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3721 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3722 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3723 MGMT_STATUS_BUSY);
3724 goto unlock;
3725 }
3726
3727 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3728 if (!cmd) {
3729 err = -ENOMEM;
3730 goto unlock;
3731 }
3732
3733 hci_req_init(&req, hdev);
3734
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003735 if (val)
3736 enable_advertising(&req);
3737 else
3738 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003739
3740 err = hci_req_run(&req, set_advertising_complete);
3741 if (err < 0)
3742 mgmt_pending_remove(cmd);
3743
3744unlock:
3745 hci_dev_unlock(hdev);
3746 return err;
3747}
3748
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003749static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3750 void *data, u16 len)
3751{
3752 struct mgmt_cp_set_static_address *cp = data;
3753 int err;
3754
3755 BT_DBG("%s", hdev->name);
3756
Marcel Holtmann62af4442013-10-02 22:10:32 -07003757 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003758 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003759 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003760
3761 if (hdev_is_powered(hdev))
3762 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3763 MGMT_STATUS_REJECTED);
3764
3765 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3766 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3767 return cmd_status(sk, hdev->id,
3768 MGMT_OP_SET_STATIC_ADDRESS,
3769 MGMT_STATUS_INVALID_PARAMS);
3770
3771 /* Two most significant bits shall be set */
3772 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3773 return cmd_status(sk, hdev->id,
3774 MGMT_OP_SET_STATIC_ADDRESS,
3775 MGMT_STATUS_INVALID_PARAMS);
3776 }
3777
3778 hci_dev_lock(hdev);
3779
3780 bacpy(&hdev->static_addr, &cp->bdaddr);
3781
3782 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3783
3784 hci_dev_unlock(hdev);
3785
3786 return err;
3787}
3788
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003789static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3790 void *data, u16 len)
3791{
3792 struct mgmt_cp_set_scan_params *cp = data;
3793 __u16 interval, window;
3794 int err;
3795
3796 BT_DBG("%s", hdev->name);
3797
3798 if (!lmp_le_capable(hdev))
3799 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3800 MGMT_STATUS_NOT_SUPPORTED);
3801
3802 interval = __le16_to_cpu(cp->interval);
3803
3804 if (interval < 0x0004 || interval > 0x4000)
3805 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3806 MGMT_STATUS_INVALID_PARAMS);
3807
3808 window = __le16_to_cpu(cp->window);
3809
3810 if (window < 0x0004 || window > 0x4000)
3811 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3812 MGMT_STATUS_INVALID_PARAMS);
3813
Marcel Holtmann899e1072013-10-14 09:55:32 -07003814 if (window > interval)
3815 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3816 MGMT_STATUS_INVALID_PARAMS);
3817
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003818 hci_dev_lock(hdev);
3819
3820 hdev->le_scan_interval = interval;
3821 hdev->le_scan_window = window;
3822
3823 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3824
3825 hci_dev_unlock(hdev);
3826
3827 return err;
3828}
3829
Johan Hedberg33e38b32013-03-15 17:07:05 -05003830static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3831{
3832 struct pending_cmd *cmd;
3833
3834 BT_DBG("status 0x%02x", status);
3835
3836 hci_dev_lock(hdev);
3837
3838 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3839 if (!cmd)
3840 goto unlock;
3841
3842 if (status) {
3843 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3844 mgmt_status(status));
3845 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003846 struct mgmt_mode *cp = cmd->param;
3847
3848 if (cp->val)
3849 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3850 else
3851 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3852
Johan Hedberg33e38b32013-03-15 17:07:05 -05003853 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3854 new_settings(hdev, cmd->sk);
3855 }
3856
3857 mgmt_pending_remove(cmd);
3858
3859unlock:
3860 hci_dev_unlock(hdev);
3861}
3862
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003863static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003864 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003865{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003866 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003867 struct pending_cmd *cmd;
3868 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003869 int err;
3870
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003871 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003872
Johan Hedberg56f87902013-10-02 13:43:13 +03003873 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3874 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003875 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3876 MGMT_STATUS_NOT_SUPPORTED);
3877
Johan Hedberga7e80f22013-01-09 16:05:19 +02003878 if (cp->val != 0x00 && cp->val != 0x01)
3879 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3880 MGMT_STATUS_INVALID_PARAMS);
3881
Johan Hedberg5400c042012-02-21 16:40:33 +02003882 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003883 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003884 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003885
3886 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003887 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003888 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003889
3890 hci_dev_lock(hdev);
3891
Johan Hedberg05cbf292013-03-15 17:07:07 -05003892 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3893 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3894 MGMT_STATUS_BUSY);
3895 goto unlock;
3896 }
3897
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003898 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3899 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3900 hdev);
3901 goto unlock;
3902 }
3903
Johan Hedberg33e38b32013-03-15 17:07:05 -05003904 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3905 data, len);
3906 if (!cmd) {
3907 err = -ENOMEM;
3908 goto unlock;
3909 }
3910
3911 hci_req_init(&req, hdev);
3912
Johan Hedberg406d7802013-03-15 17:07:09 -05003913 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003914
3915 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003916 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003917 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003918 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003919 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003920 }
3921
Johan Hedberg33e38b32013-03-15 17:07:05 -05003922unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003923 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003924
Antti Julkuf6422ec2011-06-22 13:11:56 +03003925 return err;
3926}
3927
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003928static void set_bredr_scan(struct hci_request *req)
3929{
3930 struct hci_dev *hdev = req->hdev;
3931 u8 scan = 0;
3932
3933 /* Ensure that fast connectable is disabled. This function will
3934 * not do anything if the page scan parameters are already what
3935 * they should be.
3936 */
3937 write_fast_connectable(req, false);
3938
3939 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3940 scan |= SCAN_PAGE;
3941 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3942 scan |= SCAN_INQUIRY;
3943
3944 if (scan)
3945 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3946}
3947
Johan Hedberg0663ca22013-10-02 13:43:14 +03003948static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3949{
3950 struct pending_cmd *cmd;
3951
3952 BT_DBG("status 0x%02x", status);
3953
3954 hci_dev_lock(hdev);
3955
3956 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3957 if (!cmd)
3958 goto unlock;
3959
3960 if (status) {
3961 u8 mgmt_err = mgmt_status(status);
3962
3963 /* We need to restore the flag if related HCI commands
3964 * failed.
3965 */
3966 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3967
3968 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3969 } else {
3970 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3971 new_settings(hdev, cmd->sk);
3972 }
3973
3974 mgmt_pending_remove(cmd);
3975
3976unlock:
3977 hci_dev_unlock(hdev);
3978}
3979
3980static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3981{
3982 struct mgmt_mode *cp = data;
3983 struct pending_cmd *cmd;
3984 struct hci_request req;
3985 int err;
3986
3987 BT_DBG("request for %s", hdev->name);
3988
3989 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3990 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3991 MGMT_STATUS_NOT_SUPPORTED);
3992
3993 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3994 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3995 MGMT_STATUS_REJECTED);
3996
3997 if (cp->val != 0x00 && cp->val != 0x01)
3998 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3999 MGMT_STATUS_INVALID_PARAMS);
4000
4001 hci_dev_lock(hdev);
4002
4003 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4004 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4005 goto unlock;
4006 }
4007
4008 if (!hdev_is_powered(hdev)) {
4009 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004010 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4011 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4012 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4013 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
4014 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
4015 }
4016
4017 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4018
4019 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4020 if (err < 0)
4021 goto unlock;
4022
4023 err = new_settings(hdev, sk);
4024 goto unlock;
4025 }
4026
4027 /* Reject disabling when powered on */
4028 if (!cp->val) {
4029 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4030 MGMT_STATUS_REJECTED);
4031 goto unlock;
4032 }
4033
4034 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
4035 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4036 MGMT_STATUS_BUSY);
4037 goto unlock;
4038 }
4039
4040 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4041 if (!cmd) {
4042 err = -ENOMEM;
4043 goto unlock;
4044 }
4045
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004046 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03004047 * generates the correct flags.
4048 */
4049 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4050
4051 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004052
4053 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4054 set_bredr_scan(&req);
4055
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004056 /* Since only the advertising data flags will change, there
4057 * is no need to update the scan response data.
4058 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004059 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004060
Johan Hedberg0663ca22013-10-02 13:43:14 +03004061 err = hci_req_run(&req, set_bredr_complete);
4062 if (err < 0)
4063 mgmt_pending_remove(cmd);
4064
4065unlock:
4066 hci_dev_unlock(hdev);
4067 return err;
4068}
4069
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004070static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4071 void *data, u16 len)
4072{
4073 struct mgmt_mode *cp = data;
4074 struct pending_cmd *cmd;
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004075 u8 val, status;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004076 int err;
4077
4078 BT_DBG("request for %s", hdev->name);
4079
4080 status = mgmt_bredr_support(hdev);
4081 if (status)
4082 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4083 status);
4084
Marcel Holtmann5afeac12014-01-10 02:07:27 -08004085 if (!lmp_sc_capable(hdev) &&
4086 !test_bit(HCI_FORCE_SC, &hdev->dev_flags))
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004087 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4088 MGMT_STATUS_NOT_SUPPORTED);
4089
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004090 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004091 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4092 MGMT_STATUS_INVALID_PARAMS);
4093
4094 hci_dev_lock(hdev);
4095
4096 if (!hdev_is_powered(hdev)) {
4097 bool changed;
4098
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004099 if (cp->val) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004100 changed = !test_and_set_bit(HCI_SC_ENABLED,
4101 &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004102 if (cp->val == 0x02)
4103 set_bit(HCI_SC_ONLY, &hdev->dev_flags);
4104 else
4105 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4106 } else {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004107 changed = test_and_clear_bit(HCI_SC_ENABLED,
4108 &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004109 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4110 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004111
4112 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4113 if (err < 0)
4114 goto failed;
4115
4116 if (changed)
4117 err = new_settings(hdev, sk);
4118
4119 goto failed;
4120 }
4121
4122 if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
4123 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4124 MGMT_STATUS_BUSY);
4125 goto failed;
4126 }
4127
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004128 val = !!cp->val;
4129
4130 if (val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
4131 (cp->val == 0x02) == test_bit(HCI_SC_ONLY, &hdev->dev_flags)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004132 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4133 goto failed;
4134 }
4135
4136 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4137 if (!cmd) {
4138 err = -ENOMEM;
4139 goto failed;
4140 }
4141
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004142 err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004143 if (err < 0) {
4144 mgmt_pending_remove(cmd);
4145 goto failed;
4146 }
4147
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004148 if (cp->val == 0x02)
4149 set_bit(HCI_SC_ONLY, &hdev->dev_flags);
4150 else
4151 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4152
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004153failed:
4154 hci_dev_unlock(hdev);
4155 return err;
4156}
4157
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004158static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4159 void *data, u16 len)
4160{
4161 struct mgmt_mode *cp = data;
4162 bool changed;
4163 int err;
4164
4165 BT_DBG("request for %s", hdev->name);
4166
4167 if (cp->val != 0x00 && cp->val != 0x01)
4168 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4169 MGMT_STATUS_INVALID_PARAMS);
4170
4171 hci_dev_lock(hdev);
4172
4173 if (cp->val)
4174 changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
4175 else
4176 changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
4177
4178 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4179 if (err < 0)
4180 goto unlock;
4181
4182 if (changed)
4183 err = new_settings(hdev, sk);
4184
4185unlock:
4186 hci_dev_unlock(hdev);
4187 return err;
4188}
4189
Johan Hedberg41edf162014-02-18 10:19:35 +02004190static bool irk_is_valid(struct mgmt_irk_info *irk)
4191{
4192 switch (irk->addr.type) {
4193 case BDADDR_LE_PUBLIC:
4194 return true;
4195
4196 case BDADDR_LE_RANDOM:
4197 /* Two most significant bits shall be set */
4198 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4199 return false;
4200 return true;
4201 }
4202
4203 return false;
4204}
4205
4206static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4207 u16 len)
4208{
4209 struct mgmt_cp_load_irks *cp = cp_data;
4210 u16 irk_count, expected_len;
4211 int i, err;
4212
4213 BT_DBG("request for %s", hdev->name);
4214
4215 if (!lmp_le_capable(hdev))
4216 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4217 MGMT_STATUS_NOT_SUPPORTED);
4218
4219 irk_count = __le16_to_cpu(cp->irk_count);
4220
4221 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4222 if (expected_len != len) {
4223 BT_ERR("load_irks: expected %u bytes, got %u bytes",
4224 len, expected_len);
4225 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4226 MGMT_STATUS_INVALID_PARAMS);
4227 }
4228
4229 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4230
4231 for (i = 0; i < irk_count; i++) {
4232 struct mgmt_irk_info *key = &cp->irks[i];
4233
4234 if (!irk_is_valid(key))
4235 return cmd_status(sk, hdev->id,
4236 MGMT_OP_LOAD_IRKS,
4237 MGMT_STATUS_INVALID_PARAMS);
4238 }
4239
4240 hci_dev_lock(hdev);
4241
4242 hci_smp_irks_clear(hdev);
4243
4244 for (i = 0; i < irk_count; i++) {
4245 struct mgmt_irk_info *irk = &cp->irks[i];
4246 u8 addr_type;
4247
4248 if (irk->addr.type == BDADDR_LE_PUBLIC)
4249 addr_type = ADDR_LE_DEV_PUBLIC;
4250 else
4251 addr_type = ADDR_LE_DEV_RANDOM;
4252
4253 hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
4254 BDADDR_ANY);
4255 }
4256
4257 set_bit(HCI_RPA_RESOLVING, &hdev->dev_flags);
4258
4259 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
4260
4261 hci_dev_unlock(hdev);
4262
4263 return err;
4264}
4265
Johan Hedberg3f706b72013-01-20 14:27:16 +02004266static bool ltk_is_valid(struct mgmt_ltk_info *key)
4267{
4268 if (key->master != 0x00 && key->master != 0x01)
4269 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004270
4271 switch (key->addr.type) {
4272 case BDADDR_LE_PUBLIC:
4273 return true;
4274
4275 case BDADDR_LE_RANDOM:
4276 /* Two most significant bits shall be set */
4277 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4278 return false;
4279 return true;
4280 }
4281
4282 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004283}
4284
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004285static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004286 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004287{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004288 struct mgmt_cp_load_long_term_keys *cp = cp_data;
4289 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004290 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004291
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004292 BT_DBG("request for %s", hdev->name);
4293
4294 if (!lmp_le_capable(hdev))
4295 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4296 MGMT_STATUS_NOT_SUPPORTED);
4297
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004298 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004299
4300 expected_len = sizeof(*cp) + key_count *
4301 sizeof(struct mgmt_ltk_info);
4302 if (expected_len != len) {
4303 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004304 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004305 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02004306 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004307 }
4308
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004309 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004310
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004311 for (i = 0; i < key_count; i++) {
4312 struct mgmt_ltk_info *key = &cp->keys[i];
4313
Johan Hedberg3f706b72013-01-20 14:27:16 +02004314 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004315 return cmd_status(sk, hdev->id,
4316 MGMT_OP_LOAD_LONG_TERM_KEYS,
4317 MGMT_STATUS_INVALID_PARAMS);
4318 }
4319
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004320 hci_dev_lock(hdev);
4321
4322 hci_smp_ltks_clear(hdev);
4323
4324 for (i = 0; i < key_count; i++) {
4325 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004326 u8 type, addr_type;
4327
4328 if (key->addr.type == BDADDR_LE_PUBLIC)
4329 addr_type = ADDR_LE_DEV_PUBLIC;
4330 else
4331 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004332
4333 if (key->master)
4334 type = HCI_SMP_LTK;
4335 else
4336 type = HCI_SMP_LTK_SLAVE;
4337
Johan Hedberg35d70272014-02-19 14:57:47 +02004338 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type,
4339 key->type, key->val, key->enc_size, key->ediv,
4340 key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004341 }
4342
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004343 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4344 NULL, 0);
4345
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004346 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004347
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004348 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004349}
4350
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004351static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004352 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4353 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004354 bool var_len;
4355 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004356} mgmt_handlers[] = {
4357 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004358 { read_version, false, MGMT_READ_VERSION_SIZE },
4359 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4360 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4361 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4362 { set_powered, false, MGMT_SETTING_SIZE },
4363 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4364 { set_connectable, false, MGMT_SETTING_SIZE },
4365 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4366 { set_pairable, false, MGMT_SETTING_SIZE },
4367 { set_link_security, false, MGMT_SETTING_SIZE },
4368 { set_ssp, false, MGMT_SETTING_SIZE },
4369 { set_hs, false, MGMT_SETTING_SIZE },
4370 { set_le, false, MGMT_SETTING_SIZE },
4371 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4372 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4373 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4374 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4375 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4376 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4377 { disconnect, false, MGMT_DISCONNECT_SIZE },
4378 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4379 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4380 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4381 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4382 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4383 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4384 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4385 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4386 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4387 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4388 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4389 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
Marcel Holtmannec109112014-01-10 02:07:30 -08004390 { add_remote_oob_data, true, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
Johan Hedbergbe22b542012-03-01 22:24:41 +02004391 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4392 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4393 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4394 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4395 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4396 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004397 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004398 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004399 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004400 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004401 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004402 { set_secure_conn, false, MGMT_SETTING_SIZE },
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004403 { set_debug_keys, false, MGMT_SETTING_SIZE },
Johan Hedberg41edf162014-02-18 10:19:35 +02004404 { },
4405 { load_irks, true, MGMT_LOAD_IRKS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004406};
4407
4408
Johan Hedberg03811012010-12-08 00:21:06 +02004409int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4410{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004411 void *buf;
4412 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004413 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004414 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004415 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004416 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004417 int err;
4418
4419 BT_DBG("got %zu bytes", msglen);
4420
4421 if (msglen < sizeof(*hdr))
4422 return -EINVAL;
4423
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004424 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004425 if (!buf)
4426 return -ENOMEM;
4427
4428 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4429 err = -EFAULT;
4430 goto done;
4431 }
4432
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004433 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004434 opcode = __le16_to_cpu(hdr->opcode);
4435 index = __le16_to_cpu(hdr->index);
4436 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004437
4438 if (len != msglen - sizeof(*hdr)) {
4439 err = -EINVAL;
4440 goto done;
4441 }
4442
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004443 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004444 hdev = hci_dev_get(index);
4445 if (!hdev) {
4446 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004447 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004448 goto done;
4449 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004450
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004451 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4452 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004453 err = cmd_status(sk, index, opcode,
4454 MGMT_STATUS_INVALID_INDEX);
4455 goto done;
4456 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004457 }
4458
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004459 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004460 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004461 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004462 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004463 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004464 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004465 }
4466
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004467 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004468 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004469 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004470 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004471 goto done;
4472 }
4473
Johan Hedbergbe22b542012-03-01 22:24:41 +02004474 handler = &mgmt_handlers[opcode];
4475
4476 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004477 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004478 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004479 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004480 goto done;
4481 }
4482
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004483 if (hdev)
4484 mgmt_init_hdev(sk, hdev);
4485
4486 cp = buf + sizeof(*hdr);
4487
Johan Hedbergbe22b542012-03-01 22:24:41 +02004488 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004489 if (err < 0)
4490 goto done;
4491
Johan Hedberg03811012010-12-08 00:21:06 +02004492 err = msglen;
4493
4494done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004495 if (hdev)
4496 hci_dev_put(hdev);
4497
Johan Hedberg03811012010-12-08 00:21:06 +02004498 kfree(buf);
4499 return err;
4500}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004501
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004502void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004503{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004504 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004505 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004506
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004507 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004508}
4509
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004510void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004511{
Johan Hedberg5f159032012-03-02 03:13:19 +02004512 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004513
Marcel Holtmann1514b892013-10-06 08:25:01 -07004514 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004515 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004516
Johan Hedberg744cf192011-11-08 20:40:14 +02004517 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004518
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004519 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004520}
4521
Johan Hedberg229ab392013-03-15 17:06:53 -05004522static void powered_complete(struct hci_dev *hdev, u8 status)
4523{
4524 struct cmd_lookup match = { NULL, hdev };
4525
4526 BT_DBG("status 0x%02x", status);
4527
4528 hci_dev_lock(hdev);
4529
4530 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4531
4532 new_settings(hdev, match.sk);
4533
4534 hci_dev_unlock(hdev);
4535
4536 if (match.sk)
4537 sock_put(match.sk);
4538}
4539
Johan Hedberg70da6242013-03-15 17:06:51 -05004540static int powered_update_hci(struct hci_dev *hdev)
4541{
Johan Hedberg890ea892013-03-15 17:06:52 -05004542 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004543 u8 link_sec;
4544
Johan Hedberg890ea892013-03-15 17:06:52 -05004545 hci_req_init(&req, hdev);
4546
Johan Hedberg70da6242013-03-15 17:06:51 -05004547 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4548 !lmp_host_ssp_capable(hdev)) {
4549 u8 ssp = 1;
4550
Johan Hedberg890ea892013-03-15 17:06:52 -05004551 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004552 }
4553
Johan Hedbergc73eee92013-04-19 18:35:21 +03004554 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4555 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004556 struct hci_cp_write_le_host_supported cp;
4557
4558 cp.le = 1;
4559 cp.simul = lmp_le_br_capable(hdev);
4560
4561 /* Check first if we already have the right
4562 * host state (host features set)
4563 */
4564 if (cp.le != lmp_host_le_capable(hdev) ||
4565 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004566 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4567 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004568 }
4569
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004570 if (lmp_le_capable(hdev)) {
4571 /* Set random address to static address if configured */
4572 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4573 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4574 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004575
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004576 /* Make sure the controller has a good default for
4577 * advertising data. This also applies to the case
4578 * where BR/EDR was toggled during the AUTO_OFF phase.
4579 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004580 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004581 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004582 update_scan_rsp_data(&req);
4583 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004584
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004585 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4586 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004587 }
4588
Johan Hedberg70da6242013-03-15 17:06:51 -05004589 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4590 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004591 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4592 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004593
4594 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004595 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4596 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004597 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004598 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004599 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004600 }
4601
Johan Hedberg229ab392013-03-15 17:06:53 -05004602 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004603}
4604
Johan Hedberg744cf192011-11-08 20:40:14 +02004605int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004606{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004607 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004608 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4609 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004610 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004611
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004612 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4613 return 0;
4614
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004615 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004616 if (powered_update_hci(hdev) == 0)
4617 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004618
Johan Hedberg229ab392013-03-15 17:06:53 -05004619 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4620 &match);
4621 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004622 }
4623
Johan Hedberg229ab392013-03-15 17:06:53 -05004624 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4625 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4626
4627 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4628 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4629 zero_cod, sizeof(zero_cod), NULL);
4630
4631new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004632 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004633
4634 if (match.sk)
4635 sock_put(match.sk);
4636
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004637 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004638}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004639
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004640void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004641{
4642 struct pending_cmd *cmd;
4643 u8 status;
4644
4645 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4646 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004647 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004648
4649 if (err == -ERFKILL)
4650 status = MGMT_STATUS_RFKILLED;
4651 else
4652 status = MGMT_STATUS_FAILED;
4653
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004654 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004655
4656 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004657}
4658
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004659void mgmt_discoverable_timeout(struct hci_dev *hdev)
4660{
4661 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004662
4663 hci_dev_lock(hdev);
4664
4665 /* When discoverable timeout triggers, then just make sure
4666 * the limited discoverable flag is cleared. Even in the case
4667 * of a timeout triggered from general discoverable, it is
4668 * safe to unconditionally clear the flag.
4669 */
4670 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004671 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004672
4673 hci_req_init(&req, hdev);
Johan Hedberg4b580612013-10-19 23:38:21 +03004674 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4675 u8 scan = SCAN_PAGE;
4676 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
4677 sizeof(scan), &scan);
4678 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004679 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004680 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004681 hci_req_run(&req, NULL);
4682
4683 hdev->discov_timeout = 0;
4684
Johan Hedberg9a43e252013-10-20 19:00:07 +03004685 new_settings(hdev, NULL);
4686
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004687 hci_dev_unlock(hdev);
4688}
4689
Marcel Holtmann86a75642013-10-15 06:33:54 -07004690void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004691{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004692 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004693
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004694 /* Nothing needed here if there's a pending command since that
4695 * commands request completion callback takes care of everything
4696 * necessary.
4697 */
4698 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004699 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004700
Johan Hedberg9a43e252013-10-20 19:00:07 +03004701 if (discoverable) {
Marcel Holtmann86a75642013-10-15 06:33:54 -07004702 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004703 } else {
4704 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmann86a75642013-10-15 06:33:54 -07004705 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004706 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004707
Johan Hedberg9a43e252013-10-20 19:00:07 +03004708 if (changed) {
4709 struct hci_request req;
4710
4711 /* In case this change in discoverable was triggered by
4712 * a disabling of connectable there could be a need to
4713 * update the advertising flags.
4714 */
4715 hci_req_init(&req, hdev);
4716 update_adv_data(&req);
4717 hci_req_run(&req, NULL);
4718
Marcel Holtmann86a75642013-10-15 06:33:54 -07004719 new_settings(hdev, NULL);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004720 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004721}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004722
Marcel Holtmanna3309162013-10-15 06:33:55 -07004723void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004724{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004725 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004726
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004727 /* Nothing needed here if there's a pending command since that
4728 * commands request completion callback takes care of everything
4729 * necessary.
4730 */
4731 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004732 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004733
Marcel Holtmanna3309162013-10-15 06:33:55 -07004734 if (connectable)
4735 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4736 else
4737 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004738
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004739 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004740 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004741}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004742
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004743void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004744{
Johan Hedbergca69b792011-11-11 18:10:00 +02004745 u8 mgmt_err = mgmt_status(status);
4746
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004747 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004748 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004749 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004750
4751 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004752 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004753 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004754}
4755
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004756void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4757 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004758{
Johan Hedberg86742e12011-11-07 23:13:38 +02004759 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004760
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004761 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004762
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004763 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004764 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004765 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004766 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004767 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004768 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004769
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004770 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004771}
Johan Hedbergf7520542011-01-20 12:34:39 +02004772
Johan Hedbergba74b662014-02-19 14:57:45 +02004773void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004774{
4775 struct mgmt_ev_new_long_term_key ev;
4776
4777 memset(&ev, 0, sizeof(ev));
4778
Marcel Holtmann5192d302014-02-19 17:11:58 -08004779 /* Devices using resolvable or non-resolvable random addresses
4780 * without providing an indentity resolving key don't require
4781 * to store long term keys. Their addresses will change the
4782 * next time around.
4783 *
4784 * Only when a remote device provides an identity address
4785 * make sure the long term key is stored. If the remote
4786 * identity is known, the long term keys are internally
4787 * mapped to the identity address. So allow static random
4788 * and public addresses here.
4789 */
Johan Hedbergba74b662014-02-19 14:57:45 +02004790 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
4791 (key->bdaddr.b[5] & 0xc0) != 0xc0)
4792 ev.store_hint = 0x00;
4793 else
4794 ev.store_hint = 0x01;
4795
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004796 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004797 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Marcel Holtmannd40f3ee2014-01-31 18:42:17 -08004798 ev.key.type = key->authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004799 ev.key.enc_size = key->enc_size;
4800 ev.key.ediv = key->ediv;
4801
4802 if (key->type == HCI_SMP_LTK)
4803 ev.key.master = 1;
4804
4805 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4806 memcpy(ev.key.val, key->val, sizeof(key->val));
4807
Marcel Holtmann083368f2013-10-15 14:26:29 -07004808 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004809}
4810
Johan Hedberg95fbac82014-02-19 15:18:31 +02004811void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk)
4812{
4813 struct mgmt_ev_new_irk ev;
4814
4815 memset(&ev, 0, sizeof(ev));
4816
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08004817 /* For identity resolving keys from devices that are already
4818 * using a public address or static random address, do not
4819 * ask for storing this key. The identity resolving key really
4820 * is only mandatory for devices using resovlable random
4821 * addresses.
4822 *
4823 * Storing all identity resolving keys has the downside that
4824 * they will be also loaded on next boot of they system. More
4825 * identity resolving keys, means more time during scanning is
4826 * needed to actually resolve these addresses.
4827 */
4828 if (bacmp(&irk->rpa, BDADDR_ANY))
4829 ev.store_hint = 0x01;
4830 else
4831 ev.store_hint = 0x00;
4832
Johan Hedberg95fbac82014-02-19 15:18:31 +02004833 bacpy(&ev.rpa, &irk->rpa);
4834 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
4835 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
4836 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
4837
4838 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
4839}
4840
Marcel Holtmann94933992013-10-15 10:26:39 -07004841static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4842 u8 data_len)
4843{
4844 eir[eir_len++] = sizeof(type) + data_len;
4845 eir[eir_len++] = type;
4846 memcpy(&eir[eir_len], data, data_len);
4847 eir_len += data_len;
4848
4849 return eir_len;
4850}
4851
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004852void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4853 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4854 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004855{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004856 char buf[512];
4857 struct mgmt_ev_device_connected *ev = (void *) buf;
4858 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004859
Johan Hedbergb644ba32012-01-17 21:48:47 +02004860 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004861 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004862
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004863 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004864
Johan Hedbergb644ba32012-01-17 21:48:47 +02004865 if (name_len > 0)
4866 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004867 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004868
4869 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004870 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004871 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004872
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004873 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004874
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004875 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4876 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004877}
4878
Johan Hedberg8962ee72011-01-20 12:40:27 +02004879static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4880{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004881 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004882 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004883 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004884
Johan Hedberg88c3df12012-02-09 14:27:38 +02004885 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4886 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004887
Johan Hedbergaee9b212012-02-18 15:07:59 +02004888 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004889 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004890
4891 *sk = cmd->sk;
4892 sock_hold(*sk);
4893
Johan Hedberga664b5b2011-02-19 12:06:02 -03004894 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004895}
4896
Johan Hedberg124f6e32012-02-09 13:50:12 +02004897static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004898{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004899 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004900 struct mgmt_cp_unpair_device *cp = cmd->param;
4901 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004902
4903 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004904 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4905 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004906
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004907 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4908
Johan Hedbergaee9b212012-02-18 15:07:59 +02004909 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004910
4911 mgmt_pending_remove(cmd);
4912}
4913
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004914void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4915 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004916{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004917 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004918 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004919
Andre Guedes57eb7762013-10-30 19:01:41 -03004920 if (link_type != ACL_LINK && link_type != LE_LINK)
4921 return;
4922
Johan Hedberg744cf192011-11-08 20:40:14 +02004923 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004924
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004925 bacpy(&ev.addr.bdaddr, bdaddr);
4926 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4927 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004928
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004929 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004930
4931 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004932 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004933
Johan Hedberg124f6e32012-02-09 13:50:12 +02004934 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004935 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004936}
4937
Marcel Holtmann78929242013-10-06 23:55:47 -07004938void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4939 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004940{
Andre Guedes3655bba2013-10-30 19:01:40 -03004941 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
4942 struct mgmt_cp_disconnect *cp;
Johan Hedberg88c3df12012-02-09 14:27:38 +02004943 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004944 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004945
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004946 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4947 hdev);
4948
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004949 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004950 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004951 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004952
Andre Guedes3655bba2013-10-30 19:01:40 -03004953 cp = cmd->param;
4954
4955 if (bacmp(bdaddr, &cp->addr.bdaddr))
4956 return;
4957
4958 if (cp->addr.type != bdaddr_type)
4959 return;
4960
Johan Hedberg88c3df12012-02-09 14:27:38 +02004961 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes3655bba2013-10-30 19:01:40 -03004962 rp.addr.type = bdaddr_type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004963
Marcel Holtmann78929242013-10-06 23:55:47 -07004964 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4965 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004966
Johan Hedberga664b5b2011-02-19 12:06:02 -03004967 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004968}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004969
Marcel Holtmann445608d2013-10-06 23:55:48 -07004970void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4971 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004972{
4973 struct mgmt_ev_connect_failed ev;
4974
Johan Hedberg4c659c32011-11-07 23:13:39 +02004975 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004976 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004977 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004978
Marcel Holtmann445608d2013-10-06 23:55:48 -07004979 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004980}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004981
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004982void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004983{
4984 struct mgmt_ev_pin_code_request ev;
4985
Johan Hedbergd8457692012-02-17 14:24:57 +02004986 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004987 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004988 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004989
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004990 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004991}
4992
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004993void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4994 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004995{
4996 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004997 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004998
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004999 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005000 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07005001 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005002
Johan Hedbergd8457692012-02-17 14:24:57 +02005003 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03005004 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005005
Marcel Holtmanne669cf82013-10-15 14:26:21 -07005006 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
5007 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02005008
Johan Hedberga664b5b2011-02-19 12:06:02 -03005009 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005010}
5011
Marcel Holtmann3eb38522013-10-15 14:26:22 -07005012void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
5013 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02005014{
5015 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005016 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005017
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005018 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005019 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07005020 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005021
Johan Hedbergd8457692012-02-17 14:24:57 +02005022 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03005023 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005024
Marcel Holtmann3eb38522013-10-15 14:26:22 -07005025 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
5026 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02005027
Johan Hedberga664b5b2011-02-19 12:06:02 -03005028 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005029}
Johan Hedberga5c29682011-02-19 12:05:57 -03005030
Johan Hedberg744cf192011-11-08 20:40:14 +02005031int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005032 u8 link_type, u8 addr_type, __le32 value,
5033 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03005034{
5035 struct mgmt_ev_user_confirm_request ev;
5036
Johan Hedberg744cf192011-11-08 20:40:14 +02005037 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03005038
Johan Hedberg272d90d2012-02-09 15:26:12 +02005039 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005040 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07005041 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02005042 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03005043
Johan Hedberg744cf192011-11-08 20:40:14 +02005044 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005045 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03005046}
5047
Johan Hedberg272d90d2012-02-09 15:26:12 +02005048int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03005049 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08005050{
5051 struct mgmt_ev_user_passkey_request ev;
5052
5053 BT_DBG("%s", hdev->name);
5054
Johan Hedberg272d90d2012-02-09 15:26:12 +02005055 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005056 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08005057
5058 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005059 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08005060}
5061
Brian Gix0df4c182011-11-16 13:53:13 -08005062static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03005063 u8 link_type, u8 addr_type, u8 status,
5064 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03005065{
5066 struct pending_cmd *cmd;
5067 struct mgmt_rp_user_confirm_reply rp;
5068 int err;
5069
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005070 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03005071 if (!cmd)
5072 return -ENOENT;
5073
Johan Hedberg272d90d2012-02-09 15:26:12 +02005074 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005075 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02005076 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005077 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03005078
Johan Hedberga664b5b2011-02-19 12:06:02 -03005079 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03005080
5081 return err;
5082}
5083
Johan Hedberg744cf192011-11-08 20:40:14 +02005084int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005085 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03005086{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005087 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005088 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03005089}
5090
Johan Hedberg272d90d2012-02-09 15:26:12 +02005091int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005092 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03005093{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005094 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03005095 status,
5096 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03005097}
Johan Hedberg2a611692011-02-19 12:06:00 -03005098
Brian Gix604086b2011-11-23 08:28:33 -08005099int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005100 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08005101{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005102 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005103 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08005104}
5105
Johan Hedberg272d90d2012-02-09 15:26:12 +02005106int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005107 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08005108{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005109 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03005110 status,
5111 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08005112}
5113
Johan Hedberg92a25252012-09-06 18:39:26 +03005114int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
5115 u8 link_type, u8 addr_type, u32 passkey,
5116 u8 entered)
5117{
5118 struct mgmt_ev_passkey_notify ev;
5119
5120 BT_DBG("%s", hdev->name);
5121
5122 bacpy(&ev.addr.bdaddr, bdaddr);
5123 ev.addr.type = link_to_bdaddr(link_type, addr_type);
5124 ev.passkey = __cpu_to_le32(passkey);
5125 ev.entered = entered;
5126
5127 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
5128}
5129
Marcel Holtmanne5460992013-10-15 14:26:23 -07005130void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5131 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03005132{
5133 struct mgmt_ev_auth_failed ev;
5134
Johan Hedbergbab73cb2012-02-09 16:07:29 +02005135 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005136 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02005137 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03005138
Marcel Holtmanne5460992013-10-15 14:26:23 -07005139 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03005140}
Johan Hedbergb312b1612011-03-16 14:29:37 +02005141
Marcel Holtmann464996a2013-10-15 14:26:24 -07005142void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005143{
5144 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07005145 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005146
5147 if (status) {
5148 u8 mgmt_err = mgmt_status(status);
5149 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005150 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07005151 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005152 }
5153
Marcel Holtmann464996a2013-10-15 14:26:24 -07005154 if (test_bit(HCI_AUTH, &hdev->flags))
5155 changed = !test_and_set_bit(HCI_LINK_SECURITY,
5156 &hdev->dev_flags);
5157 else
5158 changed = test_and_clear_bit(HCI_LINK_SECURITY,
5159 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02005160
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005161 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005162 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005163
Johan Hedberg47990ea2012-02-22 11:58:37 +02005164 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07005165 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005166
5167 if (match.sk)
5168 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005169}
5170
Johan Hedberg890ea892013-03-15 17:06:52 -05005171static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02005172{
Johan Hedberg890ea892013-03-15 17:06:52 -05005173 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02005174 struct hci_cp_write_eir cp;
5175
Johan Hedberg976eb202012-10-24 21:12:01 +03005176 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05005177 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02005178
Johan Hedbergc80da272012-02-22 15:38:48 +02005179 memset(hdev->eir, 0, sizeof(hdev->eir));
5180
Johan Hedbergcacaf522012-02-21 00:52:42 +02005181 memset(&cp, 0, sizeof(cp));
5182
Johan Hedberg890ea892013-03-15 17:06:52 -05005183 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02005184}
5185
Marcel Holtmann3e248562013-10-15 14:26:25 -07005186void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005187{
5188 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05005189 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005190 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005191
5192 if (status) {
5193 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005194
5195 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005196 &hdev->dev_flags)) {
5197 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07005198 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005199 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005200
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005201 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
5202 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07005203 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005204 }
5205
5206 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005207 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005208 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005209 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
5210 if (!changed)
5211 changed = test_and_clear_bit(HCI_HS_ENABLED,
5212 &hdev->dev_flags);
5213 else
5214 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005215 }
5216
5217 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
5218
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005219 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07005220 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005221
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005222 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005223 sock_put(match.sk);
5224
Johan Hedberg890ea892013-03-15 17:06:52 -05005225 hci_req_init(&req, hdev);
5226
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005227 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05005228 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005229 else
Johan Hedberg890ea892013-03-15 17:06:52 -05005230 clear_eir(&req);
5231
5232 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005233}
5234
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005235void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
5236{
5237 struct cmd_lookup match = { NULL, hdev };
5238 bool changed = false;
5239
5240 if (status) {
5241 u8 mgmt_err = mgmt_status(status);
5242
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005243 if (enable) {
5244 if (test_and_clear_bit(HCI_SC_ENABLED,
5245 &hdev->dev_flags))
5246 new_settings(hdev, NULL);
5247 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
5248 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005249
5250 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5251 cmd_status_rsp, &mgmt_err);
5252 return;
5253 }
5254
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005255 if (enable) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005256 changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005257 } else {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005258 changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005259 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
5260 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005261
5262 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5263 settings_rsp, &match);
5264
5265 if (changed)
5266 new_settings(hdev, match.sk);
5267
5268 if (match.sk)
5269 sock_put(match.sk);
5270}
5271
Johan Hedberg92da6092013-03-15 17:06:55 -05005272static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02005273{
5274 struct cmd_lookup *match = data;
5275
Johan Hedberg90e70452012-02-23 23:09:40 +02005276 if (match->sk == NULL) {
5277 match->sk = cmd->sk;
5278 sock_hold(match->sk);
5279 }
Johan Hedberg90e70452012-02-23 23:09:40 +02005280}
5281
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005282void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
5283 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005284{
Johan Hedberg90e70452012-02-23 23:09:40 +02005285 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005286
Johan Hedberg92da6092013-03-15 17:06:55 -05005287 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
5288 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
5289 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02005290
5291 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005292 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
5293 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02005294
5295 if (match.sk)
5296 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005297}
5298
Marcel Holtmann7667da32013-10-15 14:26:27 -07005299void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02005300{
Johan Hedbergb312b1612011-03-16 14:29:37 +02005301 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05005302 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005303
Johan Hedberg13928972013-03-15 17:07:00 -05005304 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07005305 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005306
5307 memset(&ev, 0, sizeof(ev));
5308 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005309 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005310
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005311 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05005312 if (!cmd) {
5313 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02005314
Johan Hedberg13928972013-03-15 17:07:00 -05005315 /* If this is a HCI command related to powering on the
5316 * HCI dev don't send any mgmt signals.
5317 */
5318 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07005319 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005320 }
5321
Marcel Holtmann7667da32013-10-15 14:26:27 -07005322 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
5323 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005324}
Szymon Jancc35938b2011-03-22 13:12:21 +01005325
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005326void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
5327 u8 *randomizer192, u8 *hash256,
5328 u8 *randomizer256, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01005329{
5330 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01005331
Johan Hedberg744cf192011-11-08 20:40:14 +02005332 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01005333
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005334 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01005335 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005336 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01005337
5338 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005339 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
5340 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01005341 } else {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005342 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
5343 hash256 && randomizer256) {
5344 struct mgmt_rp_read_local_oob_ext_data rp;
Szymon Jancc35938b2011-03-22 13:12:21 +01005345
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005346 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
5347 memcpy(rp.randomizer192, randomizer192,
5348 sizeof(rp.randomizer192));
Szymon Jancc35938b2011-03-22 13:12:21 +01005349
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005350 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
5351 memcpy(rp.randomizer256, randomizer256,
5352 sizeof(rp.randomizer256));
5353
5354 cmd_complete(cmd->sk, hdev->id,
5355 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5356 &rp, sizeof(rp));
5357 } else {
5358 struct mgmt_rp_read_local_oob_data rp;
5359
5360 memcpy(rp.hash, hash192, sizeof(rp.hash));
5361 memcpy(rp.randomizer, randomizer192,
5362 sizeof(rp.randomizer));
5363
5364 cmd_complete(cmd->sk, hdev->id,
5365 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5366 &rp, sizeof(rp));
5367 }
Szymon Jancc35938b2011-03-22 13:12:21 +01005368 }
5369
5370 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01005371}
Johan Hedberge17acd42011-03-30 23:57:16 +03005372
Marcel Holtmann901801b2013-10-06 23:55:51 -07005373void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5374 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
5375 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03005376{
Johan Hedberge319d2e2012-01-15 19:51:59 +02005377 char buf[512];
5378 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg5cedbb82014-02-18 21:41:37 +02005379 struct smp_irk *irk;
Johan Hedberg1dc06092012-01-15 21:01:23 +02005380 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03005381
Andre Guedes12602d02013-04-30 15:29:40 -03005382 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005383 return;
Andre Guedes12602d02013-04-30 15:29:40 -03005384
Johan Hedberg1dc06092012-01-15 21:01:23 +02005385 /* Leave 5 bytes for a potential CoD field */
5386 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005387 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03005388
Johan Hedberg1dc06092012-01-15 21:01:23 +02005389 memset(buf, 0, sizeof(buf));
5390
Johan Hedberg5cedbb82014-02-18 21:41:37 +02005391 irk = hci_get_irk(hdev, bdaddr, addr_type);
5392 if (irk) {
5393 bacpy(&ev->addr.bdaddr, &irk->bdaddr);
5394 ev->addr.type = link_to_bdaddr(link_type, irk->addr_type);
5395 } else {
5396 bacpy(&ev->addr.bdaddr, bdaddr);
5397 ev->addr.type = link_to_bdaddr(link_type, addr_type);
5398 }
5399
Johan Hedberge319d2e2012-01-15 19:51:59 +02005400 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02005401 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305402 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02005403 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305404 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03005405
Johan Hedberg1dc06092012-01-15 21:01:23 +02005406 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02005407 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03005408
Johan Hedberg1dc06092012-01-15 21:01:23 +02005409 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
5410 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005411 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005412
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005413 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005414 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03005415
Marcel Holtmann901801b2013-10-06 23:55:51 -07005416 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03005417}
Johan Hedberga88a9652011-03-30 13:18:12 +03005418
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005419void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5420 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03005421{
Johan Hedbergb644ba32012-01-17 21:48:47 +02005422 struct mgmt_ev_device_found *ev;
5423 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
5424 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03005425
Johan Hedbergb644ba32012-01-17 21:48:47 +02005426 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03005427
Johan Hedbergb644ba32012-01-17 21:48:47 +02005428 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03005429
Johan Hedbergb644ba32012-01-17 21:48:47 +02005430 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005431 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005432 ev->rssi = rssi;
5433
5434 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005435 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005436
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005437 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005438
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005439 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03005440}
Johan Hedberg314b2382011-04-27 10:29:57 -04005441
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005442void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04005443{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005444 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02005445 struct pending_cmd *cmd;
5446
Andre Guedes343fb142011-11-22 17:14:19 -03005447 BT_DBG("%s discovering %u", hdev->name, discovering);
5448
Johan Hedberg164a6e72011-11-01 17:06:44 +02005449 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005450 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005451 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005452 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005453
5454 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02005455 u8 type = hdev->discovery.type;
5456
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005457 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
5458 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02005459 mgmt_pending_remove(cmd);
5460 }
5461
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005462 memset(&ev, 0, sizeof(ev));
5463 ev.type = hdev->discovery.type;
5464 ev.discovering = discovering;
5465
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005466 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04005467}
Antti Julku5e762442011-08-25 16:48:02 +03005468
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005469int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005470{
5471 struct pending_cmd *cmd;
5472 struct mgmt_ev_device_blocked ev;
5473
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005474 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005475
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005476 bacpy(&ev.addr.bdaddr, bdaddr);
5477 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005478
Johan Hedberg744cf192011-11-08 20:40:14 +02005479 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005480 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005481}
5482
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005483int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005484{
5485 struct pending_cmd *cmd;
5486 struct mgmt_ev_device_unblocked ev;
5487
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005488 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005489
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005490 bacpy(&ev.addr.bdaddr, bdaddr);
5491 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005492
Johan Hedberg744cf192011-11-08 20:40:14 +02005493 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005494 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005495}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005496
5497static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5498{
5499 BT_DBG("%s status %u", hdev->name, status);
5500
5501 /* Clear the advertising mgmt setting if we failed to re-enable it */
5502 if (status) {
5503 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005504 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005505 }
5506}
5507
5508void mgmt_reenable_advertising(struct hci_dev *hdev)
5509{
5510 struct hci_request req;
5511
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005512 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005513 return;
5514
5515 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5516 return;
5517
5518 hci_req_init(&req, hdev);
5519 enable_advertising(&req);
5520
5521 /* If this fails we have no option but to let user space know
5522 * that we've disabled advertising.
5523 */
5524 if (hci_req_run(&req, adv_enable_complete) < 0) {
5525 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005526 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005527 }
5528}