blob: 4c4912e9a7c4a0c062fd625e501abd657d4ed279 [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 Holtmann404566442014-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 Hedberg62b04cd2014-02-23 19:42:27 +020084 MGMT_OP_SET_PRIVACY,
Johan Hedberg41edf162014-02-18 10:19:35 +020085 MGMT_OP_LOAD_IRKS,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020086};
87
88static const u16 mgmt_events[] = {
89 MGMT_EV_CONTROLLER_ERROR,
90 MGMT_EV_INDEX_ADDED,
91 MGMT_EV_INDEX_REMOVED,
92 MGMT_EV_NEW_SETTINGS,
93 MGMT_EV_CLASS_OF_DEV_CHANGED,
94 MGMT_EV_LOCAL_NAME_CHANGED,
95 MGMT_EV_NEW_LINK_KEY,
96 MGMT_EV_NEW_LONG_TERM_KEY,
97 MGMT_EV_DEVICE_CONNECTED,
98 MGMT_EV_DEVICE_DISCONNECTED,
99 MGMT_EV_CONNECT_FAILED,
100 MGMT_EV_PIN_CODE_REQUEST,
101 MGMT_EV_USER_CONFIRM_REQUEST,
102 MGMT_EV_USER_PASSKEY_REQUEST,
103 MGMT_EV_AUTH_FAILED,
104 MGMT_EV_DEVICE_FOUND,
105 MGMT_EV_DISCOVERING,
106 MGMT_EV_DEVICE_BLOCKED,
107 MGMT_EV_DEVICE_UNBLOCKED,
108 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300109 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800110 MGMT_EV_NEW_IRK,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200111};
112
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800113#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200114
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200115#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
116 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
117
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200118struct pending_cmd {
119 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200120 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200121 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100122 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200123 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300124 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200125};
126
Johan Hedbergca69b792011-11-11 18:10:00 +0200127/* HCI to MGMT error code conversion table */
128static u8 mgmt_status_table[] = {
129 MGMT_STATUS_SUCCESS,
130 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
131 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
132 MGMT_STATUS_FAILED, /* Hardware Failure */
133 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
134 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200135 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200136 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
137 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
138 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
139 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
140 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
141 MGMT_STATUS_BUSY, /* Command Disallowed */
142 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
143 MGMT_STATUS_REJECTED, /* Rejected Security */
144 MGMT_STATUS_REJECTED, /* Rejected Personal */
145 MGMT_STATUS_TIMEOUT, /* Host Timeout */
146 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
147 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
148 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
149 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
150 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
151 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
152 MGMT_STATUS_BUSY, /* Repeated Attempts */
153 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
154 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
155 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
156 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
157 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
158 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
159 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
160 MGMT_STATUS_FAILED, /* Unspecified Error */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
162 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
163 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
164 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
165 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
166 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
167 MGMT_STATUS_FAILED, /* Unit Link Key Used */
168 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
169 MGMT_STATUS_TIMEOUT, /* Instant Passed */
170 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
171 MGMT_STATUS_FAILED, /* Transaction Collision */
172 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
173 MGMT_STATUS_REJECTED, /* QoS Rejected */
174 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
175 MGMT_STATUS_REJECTED, /* Insufficient Security */
176 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
177 MGMT_STATUS_BUSY, /* Role Switch Pending */
178 MGMT_STATUS_FAILED, /* Slot Violation */
179 MGMT_STATUS_FAILED, /* Role Switch Failed */
180 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
181 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
182 MGMT_STATUS_BUSY, /* Host Busy Pairing */
183 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
184 MGMT_STATUS_BUSY, /* Controller Busy */
185 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
186 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
187 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
188 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
189 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
190};
191
192static u8 mgmt_status(u8 hci_status)
193{
194 if (hci_status < ARRAY_SIZE(mgmt_status_table))
195 return mgmt_status_table[hci_status];
196
197 return MGMT_STATUS_FAILED;
198}
199
Szymon Janc4e51eae2011-02-25 19:05:48 +0100200static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200201{
202 struct sk_buff *skb;
203 struct mgmt_hdr *hdr;
204 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300205 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200206
Szymon Janc34eb5252011-02-28 14:10:08 +0100207 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200208
Andre Guedes790eff42012-06-07 19:05:46 -0300209 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200210 if (!skb)
211 return -ENOMEM;
212
213 hdr = (void *) skb_put(skb, sizeof(*hdr));
214
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530215 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100216 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200217 hdr->len = cpu_to_le16(sizeof(*ev));
218
219 ev = (void *) skb_put(skb, sizeof(*ev));
220 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200221 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200222
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300223 err = sock_queue_rcv_skb(sk, skb);
224 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200225 kfree_skb(skb);
226
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300227 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200228}
229
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200230static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300231 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200232{
233 struct sk_buff *skb;
234 struct mgmt_hdr *hdr;
235 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300236 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200237
238 BT_DBG("sock %p", sk);
239
Andre Guedes790eff42012-06-07 19:05:46 -0300240 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200241 if (!skb)
242 return -ENOMEM;
243
244 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200245
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530246 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100247 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200248 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200249
Johan Hedberga38528f2011-01-22 06:46:43 +0200250 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200251 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200252 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100253
254 if (rp)
255 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200256
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300257 err = sock_queue_rcv_skb(sk, skb);
258 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200259 kfree_skb(skb);
260
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100261 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200262}
263
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300264static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
265 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200266{
267 struct mgmt_rp_read_version rp;
268
269 BT_DBG("sock %p", sk);
270
271 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200272 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200273
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200274 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300275 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200276}
277
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300278static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
279 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200280{
281 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200282 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
283 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200284 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200285 size_t rp_size;
286 int i, err;
287
288 BT_DBG("sock %p", sk);
289
290 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
291
292 rp = kmalloc(rp_size, GFP_KERNEL);
293 if (!rp)
294 return -ENOMEM;
295
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200296 rp->num_commands = __constant_cpu_to_le16(num_commands);
297 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200298
299 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
300 put_unaligned_le16(mgmt_commands[i], opcode);
301
302 for (i = 0; i < num_events; i++, opcode++)
303 put_unaligned_le16(mgmt_events[i], opcode);
304
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200305 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300306 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200307 kfree(rp);
308
309 return err;
310}
311
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300312static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
313 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200314{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200315 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200316 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200317 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300319 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200320
321 BT_DBG("sock %p", sk);
322
323 read_lock(&hci_dev_list_lock);
324
325 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300326 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700327 if (d->dev_type == HCI_BREDR)
328 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200329 }
330
Johan Hedberga38528f2011-01-22 06:46:43 +0200331 rp_len = sizeof(*rp) + (2 * count);
332 rp = kmalloc(rp_len, GFP_ATOMIC);
333 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100334 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200335 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100336 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200337
Johan Hedberg476e44c2012-10-19 20:10:46 +0300338 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200339 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200340 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200341 continue;
342
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700343 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
344 continue;
345
Marcel Holtmann1514b892013-10-06 08:25:01 -0700346 if (d->dev_type == HCI_BREDR) {
347 rp->index[count++] = cpu_to_le16(d->id);
348 BT_DBG("Added hci%u", d->id);
349 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200350 }
351
Johan Hedberg476e44c2012-10-19 20:10:46 +0300352 rp->num_controllers = cpu_to_le16(count);
353 rp_len = sizeof(*rp) + (2 * count);
354
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200355 read_unlock(&hci_dev_list_lock);
356
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200357 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300358 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200359
Johan Hedberga38528f2011-01-22 06:46:43 +0200360 kfree(rp);
361
362 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200363}
364
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200366{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200368
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200369 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200370 settings |= MGMT_SETTING_PAIRABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800371 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg03811012010-12-08 00:21:06 +0200372
Andre Guedesed3fa312012-07-24 15:03:46 -0300373 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300374 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500375 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
376 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300377 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200378 settings |= MGMT_SETTING_BREDR;
379 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700380
381 if (lmp_ssp_capable(hdev)) {
382 settings |= MGMT_SETTING_SSP;
383 settings |= MGMT_SETTING_HS;
384 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800385
Marcel Holtmann5afeac142014-01-10 02:07:27 -0800386 if (lmp_sc_capable(hdev) ||
387 test_bit(HCI_FORCE_SC, &hdev->dev_flags))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800388 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700389 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100390
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300391 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200392 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300393 settings |= MGMT_SETTING_ADVERTISING;
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200394 settings |= MGMT_SETTING_PRIVACY;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300395 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200396
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200397 return settings;
398}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200399
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200400static u32 get_current_settings(struct hci_dev *hdev)
401{
402 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200403
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200404 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100405 settings |= MGMT_SETTING_POWERED;
406
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200407 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_CONNECTABLE;
409
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500410 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
411 settings |= MGMT_SETTING_FAST_CONNECTABLE;
412
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200413 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_DISCOVERABLE;
415
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200416 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_PAIRABLE;
418
Johan Hedberg56f87902013-10-02 13:43:13 +0300419 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_BREDR;
421
Johan Hedberg06199cf2012-02-22 16:37:11 +0200422 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200423 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200424
Johan Hedberg47990ea2012-02-22 11:58:37 +0200425 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200426 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200427
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200428 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200429 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200430
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200431 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
432 settings |= MGMT_SETTING_HS;
433
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200434 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300435 settings |= MGMT_SETTING_ADVERTISING;
436
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800437 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
438 settings |= MGMT_SETTING_SECURE_CONN;
439
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800440 if (test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags))
441 settings |= MGMT_SETTING_DEBUG_KEYS;
442
Johan Hedberg0f4bd942014-02-22 19:06:35 +0200443 if (test_bit(HCI_PRIVACY, &hdev->dev_flags))
444 settings |= MGMT_SETTING_PRIVACY;
445
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200446 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200447}
448
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300449#define PNP_INFO_SVCLASS_ID 0x1200
450
Johan Hedberg213202e2013-01-27 00:31:33 +0200451static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
452{
453 u8 *ptr = data, *uuids_start = NULL;
454 struct bt_uuid *uuid;
455
456 if (len < 4)
457 return ptr;
458
459 list_for_each_entry(uuid, &hdev->uuids, list) {
460 u16 uuid16;
461
462 if (uuid->size != 16)
463 continue;
464
465 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
466 if (uuid16 < 0x1100)
467 continue;
468
469 if (uuid16 == PNP_INFO_SVCLASS_ID)
470 continue;
471
472 if (!uuids_start) {
473 uuids_start = ptr;
474 uuids_start[0] = 1;
475 uuids_start[1] = EIR_UUID16_ALL;
476 ptr += 2;
477 }
478
479 /* Stop if not enough space to put next UUID */
480 if ((ptr - data) + sizeof(u16) > len) {
481 uuids_start[1] = EIR_UUID16_SOME;
482 break;
483 }
484
485 *ptr++ = (uuid16 & 0x00ff);
486 *ptr++ = (uuid16 & 0xff00) >> 8;
487 uuids_start[0] += sizeof(uuid16);
488 }
489
490 return ptr;
491}
492
Johan Hedbergcdf19632013-01-27 00:31:34 +0200493static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
494{
495 u8 *ptr = data, *uuids_start = NULL;
496 struct bt_uuid *uuid;
497
498 if (len < 6)
499 return ptr;
500
501 list_for_each_entry(uuid, &hdev->uuids, list) {
502 if (uuid->size != 32)
503 continue;
504
505 if (!uuids_start) {
506 uuids_start = ptr;
507 uuids_start[0] = 1;
508 uuids_start[1] = EIR_UUID32_ALL;
509 ptr += 2;
510 }
511
512 /* Stop if not enough space to put next UUID */
513 if ((ptr - data) + sizeof(u32) > len) {
514 uuids_start[1] = EIR_UUID32_SOME;
515 break;
516 }
517
518 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
519 ptr += sizeof(u32);
520 uuids_start[0] += sizeof(u32);
521 }
522
523 return ptr;
524}
525
Johan Hedbergc00d5752013-01-27 00:31:35 +0200526static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
527{
528 u8 *ptr = data, *uuids_start = NULL;
529 struct bt_uuid *uuid;
530
531 if (len < 18)
532 return ptr;
533
534 list_for_each_entry(uuid, &hdev->uuids, list) {
535 if (uuid->size != 128)
536 continue;
537
538 if (!uuids_start) {
539 uuids_start = ptr;
540 uuids_start[0] = 1;
541 uuids_start[1] = EIR_UUID128_ALL;
542 ptr += 2;
543 }
544
545 /* Stop if not enough space to put next UUID */
546 if ((ptr - data) + 16 > len) {
547 uuids_start[1] = EIR_UUID128_SOME;
548 break;
549 }
550
551 memcpy(ptr, uuid->uuid, 16);
552 ptr += 16;
553 uuids_start[0] += 16;
554 }
555
556 return ptr;
557}
558
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300559static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
560{
561 struct pending_cmd *cmd;
562
563 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
564 if (cmd->opcode == opcode)
565 return cmd;
566 }
567
568 return NULL;
569}
570
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700571static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
572{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700573 u8 ad_len = 0;
574 size_t name_len;
575
576 name_len = strlen(hdev->dev_name);
577 if (name_len > 0) {
578 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
579
580 if (name_len > max_len) {
581 name_len = max_len;
582 ptr[1] = EIR_NAME_SHORT;
583 } else
584 ptr[1] = EIR_NAME_COMPLETE;
585
586 ptr[0] = name_len + 1;
587
588 memcpy(ptr + 2, hdev->dev_name, name_len);
589
590 ad_len += (name_len + 2);
591 ptr += (name_len + 2);
592 }
593
594 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700595}
596
597static void update_scan_rsp_data(struct hci_request *req)
598{
599 struct hci_dev *hdev = req->hdev;
600 struct hci_cp_le_set_scan_rsp_data cp;
601 u8 len;
602
Johan Hedberg7751ef12013-10-19 23:38:15 +0300603 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700604 return;
605
606 memset(&cp, 0, sizeof(cp));
607
608 len = create_scan_rsp_data(hdev, cp.data);
609
Johan Hedbergeb438b52013-10-16 15:31:07 +0300610 if (hdev->scan_rsp_data_len == len &&
611 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700612 return;
613
Johan Hedbergeb438b52013-10-16 15:31:07 +0300614 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
615 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700616
617 cp.length = len;
618
619 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
620}
621
Johan Hedberg9a43e252013-10-20 19:00:07 +0300622static u8 get_adv_discov_flags(struct hci_dev *hdev)
623{
624 struct pending_cmd *cmd;
625
626 /* If there's a pending mgmt command the flags will not yet have
627 * their final values, so check for this first.
628 */
629 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
630 if (cmd) {
631 struct mgmt_mode *cp = cmd->param;
632 if (cp->val == 0x01)
633 return LE_AD_GENERAL;
634 else if (cp->val == 0x02)
635 return LE_AD_LIMITED;
636 } else {
637 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
638 return LE_AD_LIMITED;
639 else if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
640 return LE_AD_GENERAL;
641 }
642
643 return 0;
644}
645
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700646static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700647{
648 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700649
Johan Hedberg9a43e252013-10-20 19:00:07 +0300650 flags |= get_adv_discov_flags(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700651
Johan Hedberge8340042014-01-30 11:16:50 -0800652 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700653 flags |= LE_AD_NO_BREDR;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700654
655 if (flags) {
656 BT_DBG("adv flags 0x%02x", flags);
657
658 ptr[0] = 2;
659 ptr[1] = EIR_FLAGS;
660 ptr[2] = flags;
661
662 ad_len += 3;
663 ptr += 3;
664 }
665
666 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
667 ptr[0] = 2;
668 ptr[1] = EIR_TX_POWER;
669 ptr[2] = (u8) hdev->adv_tx_power;
670
671 ad_len += 3;
672 ptr += 3;
673 }
674
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700675 return ad_len;
676}
677
Marcel Holtmann5947f4b2013-10-16 00:16:50 -0700678static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700679{
680 struct hci_dev *hdev = req->hdev;
681 struct hci_cp_le_set_adv_data cp;
682 u8 len;
683
Johan Hedberg10994ce2013-10-19 23:38:16 +0300684 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700685 return;
686
687 memset(&cp, 0, sizeof(cp));
688
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700689 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700690
691 if (hdev->adv_data_len == len &&
692 memcmp(cp.data, hdev->adv_data, len) == 0)
693 return;
694
695 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
696 hdev->adv_data_len = len;
697
698 cp.length = len;
699
700 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
701}
702
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300703static void create_eir(struct hci_dev *hdev, u8 *data)
704{
705 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300706 size_t name_len;
707
708 name_len = strlen(hdev->dev_name);
709
710 if (name_len > 0) {
711 /* EIR Data type */
712 if (name_len > 48) {
713 name_len = 48;
714 ptr[1] = EIR_NAME_SHORT;
715 } else
716 ptr[1] = EIR_NAME_COMPLETE;
717
718 /* EIR Data length */
719 ptr[0] = name_len + 1;
720
721 memcpy(ptr + 2, hdev->dev_name, name_len);
722
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300723 ptr += (name_len + 2);
724 }
725
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100726 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700727 ptr[0] = 2;
728 ptr[1] = EIR_TX_POWER;
729 ptr[2] = (u8) hdev->inq_tx_power;
730
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700731 ptr += 3;
732 }
733
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700734 if (hdev->devid_source > 0) {
735 ptr[0] = 9;
736 ptr[1] = EIR_DEVICE_ID;
737
738 put_unaligned_le16(hdev->devid_source, ptr + 2);
739 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
740 put_unaligned_le16(hdev->devid_product, ptr + 6);
741 put_unaligned_le16(hdev->devid_version, ptr + 8);
742
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700743 ptr += 10;
744 }
745
Johan Hedberg213202e2013-01-27 00:31:33 +0200746 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200747 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200748 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300749}
750
Johan Hedberg890ea892013-03-15 17:06:52 -0500751static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300752{
Johan Hedberg890ea892013-03-15 17:06:52 -0500753 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300754 struct hci_cp_write_eir cp;
755
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200756 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500757 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200758
Johan Hedberg976eb202012-10-24 21:12:01 +0300759 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500760 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300761
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200762 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500763 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300764
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200765 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500766 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300767
768 memset(&cp, 0, sizeof(cp));
769
770 create_eir(hdev, cp.data);
771
772 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500773 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300774
775 memcpy(hdev->eir, cp.data, sizeof(cp.data));
776
Johan Hedberg890ea892013-03-15 17:06:52 -0500777 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300778}
779
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200780static u8 get_service_classes(struct hci_dev *hdev)
781{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300782 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200783 u8 val = 0;
784
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300785 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200786 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200787
788 return val;
789}
790
Johan Hedberg890ea892013-03-15 17:06:52 -0500791static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200792{
Johan Hedberg890ea892013-03-15 17:06:52 -0500793 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200794 u8 cod[3];
795
796 BT_DBG("%s", hdev->name);
797
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200798 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500799 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200800
Johan Hedbergf87ea1d2013-10-19 23:38:17 +0300801 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
802 return;
803
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200804 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500805 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200806
807 cod[0] = hdev->minor_class;
808 cod[1] = hdev->major_class;
809 cod[2] = get_service_classes(hdev);
810
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700811 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
812 cod[1] |= 0x20;
813
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200814 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500815 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200816
Johan Hedberg890ea892013-03-15 17:06:52 -0500817 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200818}
819
Johan Hedberga4858cb2014-02-25 19:56:31 +0200820static bool get_connectable(struct hci_dev *hdev)
Johan Hedberg199a2fb2014-02-22 19:06:33 +0200821{
822 struct pending_cmd *cmd;
Johan Hedberg199a2fb2014-02-22 19:06:33 +0200823
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;
Johan Hedberga4858cb2014-02-25 19:56:31 +0200830 return cp->val;
Johan Hedberg199a2fb2014-02-22 19:06:33 +0200831 }
832
Johan Hedberga4858cb2014-02-25 19:56:31 +0200833 return test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg199a2fb2014-02-22 19:06:33 +0200834}
835
836static void enable_advertising(struct hci_request *req)
837{
838 struct hci_dev *hdev = req->hdev;
839 struct hci_cp_le_set_adv_param cp;
Johan Hedberg8f2a0602014-02-23 19:42:23 +0200840 u8 own_addr_type, enable = 0x01;
Johan Hedberga4858cb2014-02-25 19:56:31 +0200841 bool connectable;
Johan Hedberg199a2fb2014-02-22 19:06:33 +0200842
Johan Hedberga4858cb2014-02-25 19:56:31 +0200843 connectable = get_connectable(hdev);
Johan Hedberg8f2a0602014-02-23 19:42:23 +0200844
Johan Hedberga4858cb2014-02-25 19:56:31 +0200845 /* Set require_privacy to true only when non-connectable
846 * advertising is used. In that case it is fine to use a
847 * non-resolvable private address.
848 */
849 if (hci_update_random_address(req, !connectable, &own_addr_type) < 0)
Johan Hedberg8f2a0602014-02-23 19:42:23 +0200850 return;
851
Marcel Holtmann41c90c12014-02-23 20:25:55 -0800852 memset(&cp, 0, sizeof(cp));
Johan Hedberg199a2fb2014-02-22 19:06:33 +0200853 cp.min_interval = __constant_cpu_to_le16(0x0800);
854 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberga4858cb2014-02-25 19:56:31 +0200855 cp.type = connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
Johan Hedberg8f2a0602014-02-23 19:42:23 +0200856 cp.own_address_type = own_addr_type;
Johan Hedberg199a2fb2014-02-22 19:06:33 +0200857 cp.channel_map = hdev->le_adv_channel_map;
858
859 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
860
861 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
862}
863
864static void disable_advertising(struct hci_request *req)
865{
866 u8 enable = 0x00;
867
868 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
869}
870
Johan Hedberg7d785252011-12-15 00:47:39 +0200871static void service_cache_off(struct work_struct *work)
872{
873 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300874 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500875 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200876
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200877 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200878 return;
879
Johan Hedberg890ea892013-03-15 17:06:52 -0500880 hci_req_init(&req, hdev);
881
Johan Hedberg7d785252011-12-15 00:47:39 +0200882 hci_dev_lock(hdev);
883
Johan Hedberg890ea892013-03-15 17:06:52 -0500884 update_eir(&req);
885 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200886
887 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500888
889 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200890}
891
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200892static void rpa_expired(struct work_struct *work)
893{
894 struct hci_dev *hdev = container_of(work, struct hci_dev,
895 rpa_expired.work);
896 struct hci_request req;
897
898 BT_DBG("");
899
900 set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
901
902 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags) ||
903 hci_conn_num(hdev, LE_LINK) > 0)
904 return;
905
906 /* The generation of a new RPA and programming it into the
907 * controller happens in the enable_advertising() function.
908 */
909
910 hci_req_init(&req, hdev);
911
912 disable_advertising(&req);
913 enable_advertising(&req);
914
915 hci_req_run(&req, NULL);
916}
917
Johan Hedberg6a919082012-02-28 06:17:26 +0200918static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200919{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200920 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200921 return;
922
Johan Hedberg4f87da82012-03-02 19:55:56 +0200923 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200924 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +0200925
Johan Hedberg4f87da82012-03-02 19:55:56 +0200926 /* Non-mgmt controlled devices get this bit set
927 * implicitly so that pairing works for them, however
928 * for mgmt we require user-space to explicitly enable
929 * it
930 */
931 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200932}
933
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200934static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300935 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200936{
937 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200938
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200939 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200940
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300941 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200942
Johan Hedberg03811012010-12-08 00:21:06 +0200943 memset(&rp, 0, sizeof(rp));
944
Johan Hedberg03811012010-12-08 00:21:06 +0200945 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200946
947 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200948 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200949
950 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
951 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
952
953 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200954
955 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200956 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200957
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300958 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200959
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200960 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300961 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200962}
963
964static void mgmt_pending_free(struct pending_cmd *cmd)
965{
966 sock_put(cmd->sk);
967 kfree(cmd->param);
968 kfree(cmd);
969}
970
971static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300972 struct hci_dev *hdev, void *data,
973 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200974{
975 struct pending_cmd *cmd;
976
Andre Guedes12b94562012-06-07 19:05:45 -0300977 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200978 if (!cmd)
979 return NULL;
980
981 cmd->opcode = opcode;
982 cmd->index = hdev->id;
983
Andre Guedes12b94562012-06-07 19:05:45 -0300984 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200985 if (!cmd->param) {
986 kfree(cmd);
987 return NULL;
988 }
989
990 if (data)
991 memcpy(cmd->param, data, len);
992
993 cmd->sk = sk;
994 sock_hold(sk);
995
996 list_add(&cmd->list, &hdev->mgmt_pending);
997
998 return cmd;
999}
1000
1001static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001002 void (*cb)(struct pending_cmd *cmd,
1003 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001004 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02001005{
Andre Guedesa3d09352013-02-01 11:21:30 -03001006 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +02001007
Andre Guedesa3d09352013-02-01 11:21:30 -03001008 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +02001009 if (opcode > 0 && cmd->opcode != opcode)
1010 continue;
1011
1012 cb(cmd, data);
1013 }
1014}
1015
Johan Hedberg03811012010-12-08 00:21:06 +02001016static void mgmt_pending_remove(struct pending_cmd *cmd)
1017{
1018 list_del(&cmd->list);
1019 mgmt_pending_free(cmd);
1020}
1021
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001022static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001023{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001024 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001025
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001026 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001027 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001028}
1029
Johan Hedberg8b064a32014-02-24 14:52:22 +02001030static void clean_up_hci_complete(struct hci_dev *hdev, u8 status)
1031{
1032 BT_DBG("%s status 0x%02x", hdev->name, status);
1033
1034 if (hci_conn_count(hdev) == 0)
1035 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1036}
1037
1038static int clean_up_hci_state(struct hci_dev *hdev)
1039{
1040 struct hci_request req;
1041 struct hci_conn *conn;
1042
1043 hci_req_init(&req, hdev);
1044
1045 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1046 test_bit(HCI_PSCAN, &hdev->flags)) {
1047 u8 scan = 0x00;
1048 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1049 }
1050
1051 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1052 disable_advertising(&req);
1053
1054 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
Andre Guedesb1efcc22014-02-26 20:21:40 -03001055 hci_req_add_le_scan_disable(&req);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001056 }
1057
1058 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
1059 struct hci_cp_disconnect dc;
1060
1061 dc.handle = cpu_to_le16(conn->handle);
1062 dc.reason = 0x15; /* Terminated due to Power Off */
1063 hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1064 }
1065
1066 return hci_req_run(&req, clean_up_hci_complete);
1067}
1068
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001069static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001070 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001071{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001072 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001073 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001074 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001075
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001076 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001077
Johan Hedberga7e80f22013-01-09 16:05:19 +02001078 if (cp->val != 0x00 && cp->val != 0x01)
1079 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1080 MGMT_STATUS_INVALID_PARAMS);
1081
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001082 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001083
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001084 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
1085 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1086 MGMT_STATUS_BUSY);
1087 goto failed;
1088 }
1089
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001090 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
1091 cancel_delayed_work(&hdev->power_off);
1092
1093 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +02001094 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
1095 data, len);
1096 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001097 goto failed;
1098 }
1099 }
1100
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001101 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001102 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001103 goto failed;
1104 }
1105
Johan Hedberg03811012010-12-08 00:21:06 +02001106 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1107 if (!cmd) {
1108 err = -ENOMEM;
1109 goto failed;
1110 }
1111
Johan Hedberg8b064a32014-02-24 14:52:22 +02001112 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001113 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001114 err = 0;
1115 } else {
1116 /* Disconnect connections, stop scans, etc */
1117 err = clean_up_hci_state(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001118
Johan Hedberg8b064a32014-02-24 14:52:22 +02001119 /* ENODATA means there were no HCI commands queued */
1120 if (err == -ENODATA) {
1121 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1122 err = 0;
1123 }
1124 }
Johan Hedberg03811012010-12-08 00:21:06 +02001125
1126failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001127 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001128 return err;
1129}
1130
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001131static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
1132 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001133{
1134 struct sk_buff *skb;
1135 struct mgmt_hdr *hdr;
1136
Andre Guedes790eff42012-06-07 19:05:46 -03001137 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001138 if (!skb)
1139 return -ENOMEM;
1140
1141 hdr = (void *) skb_put(skb, sizeof(*hdr));
1142 hdr->opcode = cpu_to_le16(event);
1143 if (hdev)
1144 hdr->index = cpu_to_le16(hdev->id);
1145 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05301146 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001147 hdr->len = cpu_to_le16(data_len);
1148
1149 if (data)
1150 memcpy(skb_put(skb, data_len), data, data_len);
1151
Marcel Holtmann97e0bde2012-02-22 13:49:28 +01001152 /* Time stamp */
1153 __net_timestamp(skb);
1154
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001155 hci_send_to_control(skb, skip_sk);
1156 kfree_skb(skb);
1157
1158 return 0;
1159}
1160
1161static int new_settings(struct hci_dev *hdev, struct sock *skip)
1162{
1163 __le32 ev;
1164
1165 ev = cpu_to_le32(get_current_settings(hdev));
1166
1167 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1168}
1169
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001170struct cmd_lookup {
1171 struct sock *sk;
1172 struct hci_dev *hdev;
1173 u8 mgmt_status;
1174};
1175
1176static void settings_rsp(struct pending_cmd *cmd, void *data)
1177{
1178 struct cmd_lookup *match = data;
1179
1180 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1181
1182 list_del(&cmd->list);
1183
1184 if (match->sk == NULL) {
1185 match->sk = cmd->sk;
1186 sock_hold(match->sk);
1187 }
1188
1189 mgmt_pending_free(cmd);
1190}
1191
1192static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1193{
1194 u8 *status = data;
1195
1196 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1197 mgmt_pending_remove(cmd);
1198}
1199
Johan Hedberge6fe7982013-10-02 15:45:22 +03001200static u8 mgmt_bredr_support(struct hci_dev *hdev)
1201{
1202 if (!lmp_bredr_capable(hdev))
1203 return MGMT_STATUS_NOT_SUPPORTED;
1204 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1205 return MGMT_STATUS_REJECTED;
1206 else
1207 return MGMT_STATUS_SUCCESS;
1208}
1209
1210static u8 mgmt_le_support(struct hci_dev *hdev)
1211{
1212 if (!lmp_le_capable(hdev))
1213 return MGMT_STATUS_NOT_SUPPORTED;
1214 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1215 return MGMT_STATUS_REJECTED;
1216 else
1217 return MGMT_STATUS_SUCCESS;
1218}
1219
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001220static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1221{
1222 struct pending_cmd *cmd;
1223 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001224 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001225 bool changed;
1226
1227 BT_DBG("status 0x%02x", status);
1228
1229 hci_dev_lock(hdev);
1230
1231 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1232 if (!cmd)
1233 goto unlock;
1234
1235 if (status) {
1236 u8 mgmt_err = mgmt_status(status);
1237 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001238 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001239 goto remove_cmd;
1240 }
1241
1242 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001243 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001244 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1245 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001246
1247 if (hdev->discov_timeout > 0) {
1248 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1249 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1250 to);
1251 }
1252 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001253 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1254 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001255 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001256
1257 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1258
1259 if (changed)
1260 new_settings(hdev, cmd->sk);
1261
Marcel Holtmann970ba522013-10-15 06:33:57 -07001262 /* When the discoverable mode gets changed, make sure
1263 * that class of device has the limited discoverable
1264 * bit correctly set.
1265 */
1266 hci_req_init(&req, hdev);
1267 update_class(&req);
1268 hci_req_run(&req, NULL);
1269
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001270remove_cmd:
1271 mgmt_pending_remove(cmd);
1272
1273unlock:
1274 hci_dev_unlock(hdev);
1275}
1276
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001277static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001278 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001279{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001280 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001281 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001282 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001283 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001284 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001285 int err;
1286
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001287 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001288
Johan Hedberg9a43e252013-10-20 19:00:07 +03001289 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1290 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001291 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberg9a43e252013-10-20 19:00:07 +03001292 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001293
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001294 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga7e80f22013-01-09 16:05:19 +02001295 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1296 MGMT_STATUS_INVALID_PARAMS);
1297
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001298 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001299
1300 /* Disabling discoverable requires that no timeout is set,
1301 * and enabling limited discoverable requires a timeout.
1302 */
1303 if ((cp->val == 0x00 && timeout > 0) ||
1304 (cp->val == 0x02 && timeout == 0))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001305 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001306 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001307
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001308 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001309
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001310 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001311 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001312 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001313 goto failed;
1314 }
1315
1316 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001317 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001318 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001319 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001320 goto failed;
1321 }
1322
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001323 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001324 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001325 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001326 goto failed;
1327 }
1328
1329 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001330 bool changed = false;
1331
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001332 /* Setting limited discoverable when powered off is
1333 * not a valid operation since it requires a timeout
1334 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1335 */
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001336 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1337 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1338 changed = true;
1339 }
1340
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001341 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001342 if (err < 0)
1343 goto failed;
1344
1345 if (changed)
1346 err = new_settings(hdev, sk);
1347
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001348 goto failed;
1349 }
1350
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001351 /* If the current mode is the same, then just update the timeout
1352 * value with the new value. And if only the timeout gets updated,
1353 * then no need for any HCI transactions.
1354 */
1355 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) &&
1356 (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE,
1357 &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001358 cancel_delayed_work(&hdev->discov_off);
1359 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001360
Marcel Holtmann36261542013-10-15 08:28:51 -07001361 if (cp->val && hdev->discov_timeout > 0) {
1362 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001363 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001364 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001365 }
1366
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001367 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001368 goto failed;
1369 }
1370
1371 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1372 if (!cmd) {
1373 err = -ENOMEM;
1374 goto failed;
1375 }
1376
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001377 /* Cancel any potential discoverable timeout that might be
1378 * still active and store new timeout value. The arming of
1379 * the timeout happens in the complete handler.
1380 */
1381 cancel_delayed_work(&hdev->discov_off);
1382 hdev->discov_timeout = timeout;
1383
Johan Hedbergb456f872013-10-19 23:38:22 +03001384 /* Limited discoverable mode */
1385 if (cp->val == 0x02)
1386 set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1387 else
1388 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1389
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001390 hci_req_init(&req, hdev);
1391
Johan Hedberg9a43e252013-10-20 19:00:07 +03001392 /* The procedure for LE-only controllers is much simpler - just
1393 * update the advertising data.
1394 */
1395 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1396 goto update_ad;
1397
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001398 scan = SCAN_PAGE;
1399
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001400 if (cp->val) {
1401 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001402
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001403 if (cp->val == 0x02) {
1404 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001405 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001406 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1407 hci_cp.iac_lap[1] = 0x8b;
1408 hci_cp.iac_lap[2] = 0x9e;
1409 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1410 hci_cp.iac_lap[4] = 0x8b;
1411 hci_cp.iac_lap[5] = 0x9e;
1412 } else {
1413 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001414 hci_cp.num_iac = 1;
1415 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1416 hci_cp.iac_lap[1] = 0x8b;
1417 hci_cp.iac_lap[2] = 0x9e;
1418 }
1419
1420 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1421 (hci_cp.num_iac * 3) + 1, &hci_cp);
1422
1423 scan |= SCAN_INQUIRY;
1424 } else {
1425 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1426 }
1427
1428 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001429
Johan Hedberg9a43e252013-10-20 19:00:07 +03001430update_ad:
1431 update_adv_data(&req);
1432
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001433 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001434 if (err < 0)
1435 mgmt_pending_remove(cmd);
1436
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001437failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001438 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001439 return err;
1440}
1441
Johan Hedberg406d7802013-03-15 17:07:09 -05001442static void write_fast_connectable(struct hci_request *req, bool enable)
1443{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001444 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001445 struct hci_cp_write_page_scan_activity acp;
1446 u8 type;
1447
Johan Hedberg547003b2013-10-21 16:51:53 +03001448 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1449 return;
1450
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001451 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1452 return;
1453
Johan Hedberg406d7802013-03-15 17:07:09 -05001454 if (enable) {
1455 type = PAGE_SCAN_TYPE_INTERLACED;
1456
1457 /* 160 msec page scan interval */
1458 acp.interval = __constant_cpu_to_le16(0x0100);
1459 } else {
1460 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1461
1462 /* default 1.28 sec page scan */
1463 acp.interval = __constant_cpu_to_le16(0x0800);
1464 }
1465
1466 acp.window = __constant_cpu_to_le16(0x0012);
1467
Johan Hedbergbd98b992013-03-15 17:07:13 -05001468 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1469 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1470 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1471 sizeof(acp), &acp);
1472
1473 if (hdev->page_scan_type != type)
1474 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001475}
1476
Johan Hedberg2b76f452013-03-15 17:07:04 -05001477static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1478{
1479 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001480 struct mgmt_mode *cp;
1481 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001482
1483 BT_DBG("status 0x%02x", status);
1484
1485 hci_dev_lock(hdev);
1486
1487 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1488 if (!cmd)
1489 goto unlock;
1490
Johan Hedberg37438c12013-10-14 16:20:05 +03001491 if (status) {
1492 u8 mgmt_err = mgmt_status(status);
1493 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1494 goto remove_cmd;
1495 }
1496
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001497 cp = cmd->param;
1498 if (cp->val)
1499 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1500 else
1501 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1502
Johan Hedberg2b76f452013-03-15 17:07:04 -05001503 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1504
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001505 if (changed)
1506 new_settings(hdev, cmd->sk);
1507
Johan Hedberg37438c12013-10-14 16:20:05 +03001508remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001509 mgmt_pending_remove(cmd);
1510
1511unlock:
1512 hci_dev_unlock(hdev);
1513}
1514
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001515static int set_connectable_update_settings(struct hci_dev *hdev,
1516 struct sock *sk, u8 val)
1517{
1518 bool changed = false;
1519 int err;
1520
1521 if (!!val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1522 changed = true;
1523
1524 if (val) {
1525 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1526 } else {
1527 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1528 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1529 }
1530
1531 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1532 if (err < 0)
1533 return err;
1534
1535 if (changed)
1536 return new_settings(hdev, sk);
1537
1538 return 0;
1539}
1540
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001541static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001542 u16 len)
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001543{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001544 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001545 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001546 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001547 u8 scan;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001548 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001549
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001550 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001551
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001552 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1553 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001554 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001555 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001556
Johan Hedberga7e80f22013-01-09 16:05:19 +02001557 if (cp->val != 0x00 && cp->val != 0x01)
1558 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1559 MGMT_STATUS_INVALID_PARAMS);
1560
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001561 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001562
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001563 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001564 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001565 goto failed;
1566 }
1567
1568 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001569 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001570 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001571 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001572 goto failed;
1573 }
1574
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001575 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1576 if (!cmd) {
1577 err = -ENOMEM;
1578 goto failed;
1579 }
1580
Johan Hedberg2b76f452013-03-15 17:07:04 -05001581 hci_req_init(&req, hdev);
1582
Johan Hedberg9a43e252013-10-20 19:00:07 +03001583 /* If BR/EDR is not enabled and we disable advertising as a
1584 * by-product of disabling connectable, we need to update the
1585 * advertising flags.
1586 */
1587 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
1588 if (!cp->val) {
1589 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1590 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1591 }
1592 update_adv_data(&req);
1593 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001594 if (cp->val) {
1595 scan = SCAN_PAGE;
1596 } else {
1597 scan = 0;
1598
1599 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001600 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001601 cancel_delayed_work(&hdev->discov_off);
1602 }
1603
1604 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1605 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001606
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001607 /* If we're going from non-connectable to connectable or
1608 * vice-versa when fast connectable is enabled ensure that fast
1609 * connectable gets disabled. write_fast_connectable won't do
1610 * anything if the page scan parameters are already what they
1611 * should be.
1612 */
1613 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001614 write_fast_connectable(&req, false);
1615
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001616 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1617 hci_conn_num(hdev, LE_LINK) == 0) {
1618 disable_advertising(&req);
1619 enable_advertising(&req);
1620 }
1621
Johan Hedberg2b76f452013-03-15 17:07:04 -05001622 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001623 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001624 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001625 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03001626 err = set_connectable_update_settings(hdev, sk,
1627 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03001628 goto failed;
1629 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001630
1631failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001632 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001633 return err;
1634}
1635
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001636static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001637 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001638{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001639 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001640 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001641 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001642
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001643 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001644
Johan Hedberga7e80f22013-01-09 16:05:19 +02001645 if (cp->val != 0x00 && cp->val != 0x01)
1646 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1647 MGMT_STATUS_INVALID_PARAMS);
1648
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001649 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001650
1651 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001652 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001653 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001654 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001655
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001656 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001657 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001658 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001659
Marcel Holtmann55594352013-10-06 16:11:57 -07001660 if (changed)
1661 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001662
Marcel Holtmann55594352013-10-06 16:11:57 -07001663unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001664 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001665 return err;
1666}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001667
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001668static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1669 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001670{
1671 struct mgmt_mode *cp = data;
1672 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001673 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001674 int err;
1675
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001676 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001677
Johan Hedberge6fe7982013-10-02 15:45:22 +03001678 status = mgmt_bredr_support(hdev);
1679 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001680 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001681 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001682
Johan Hedberga7e80f22013-01-09 16:05:19 +02001683 if (cp->val != 0x00 && cp->val != 0x01)
1684 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1685 MGMT_STATUS_INVALID_PARAMS);
1686
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001687 hci_dev_lock(hdev);
1688
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001689 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001690 bool changed = false;
1691
1692 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001693 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001694 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1695 changed = true;
1696 }
1697
1698 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1699 if (err < 0)
1700 goto failed;
1701
1702 if (changed)
1703 err = new_settings(hdev, sk);
1704
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001705 goto failed;
1706 }
1707
1708 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001709 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001710 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001711 goto failed;
1712 }
1713
1714 val = !!cp->val;
1715
1716 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1717 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1718 goto failed;
1719 }
1720
1721 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1722 if (!cmd) {
1723 err = -ENOMEM;
1724 goto failed;
1725 }
1726
1727 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1728 if (err < 0) {
1729 mgmt_pending_remove(cmd);
1730 goto failed;
1731 }
1732
1733failed:
1734 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001735 return err;
1736}
1737
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001738static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001739{
1740 struct mgmt_mode *cp = data;
1741 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001742 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001743 int err;
1744
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001745 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001746
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001747 status = mgmt_bredr_support(hdev);
1748 if (status)
1749 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1750
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001751 if (!lmp_ssp_capable(hdev))
1752 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1753 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001754
Johan Hedberga7e80f22013-01-09 16:05:19 +02001755 if (cp->val != 0x00 && cp->val != 0x01)
1756 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1757 MGMT_STATUS_INVALID_PARAMS);
1758
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001759 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001760
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001761 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001762 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001763
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001764 if (cp->val) {
1765 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1766 &hdev->dev_flags);
1767 } else {
1768 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1769 &hdev->dev_flags);
1770 if (!changed)
1771 changed = test_and_clear_bit(HCI_HS_ENABLED,
1772 &hdev->dev_flags);
1773 else
1774 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001775 }
1776
1777 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1778 if (err < 0)
1779 goto failed;
1780
1781 if (changed)
1782 err = new_settings(hdev, sk);
1783
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001784 goto failed;
1785 }
1786
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001787 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1788 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001789 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1790 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001791 goto failed;
1792 }
1793
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001794 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001795 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1796 goto failed;
1797 }
1798
1799 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1800 if (!cmd) {
1801 err = -ENOMEM;
1802 goto failed;
1803 }
1804
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001805 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001806 if (err < 0) {
1807 mgmt_pending_remove(cmd);
1808 goto failed;
1809 }
1810
1811failed:
1812 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001813 return err;
1814}
1815
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001816static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001817{
1818 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001819 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001820 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001821 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001822
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001823 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001824
Johan Hedberge6fe7982013-10-02 15:45:22 +03001825 status = mgmt_bredr_support(hdev);
1826 if (status)
1827 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001828
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001829 if (!lmp_ssp_capable(hdev))
1830 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1831 MGMT_STATUS_NOT_SUPPORTED);
1832
1833 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1834 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1835 MGMT_STATUS_REJECTED);
1836
Johan Hedberga7e80f22013-01-09 16:05:19 +02001837 if (cp->val != 0x00 && cp->val != 0x01)
1838 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1839 MGMT_STATUS_INVALID_PARAMS);
1840
Marcel Holtmannee392692013-10-01 22:59:23 -07001841 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001842
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001843 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001844 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001845 } else {
1846 if (hdev_is_powered(hdev)) {
1847 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1848 MGMT_STATUS_REJECTED);
1849 goto unlock;
1850 }
1851
Marcel Holtmannee392692013-10-01 22:59:23 -07001852 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001853 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001854
1855 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1856 if (err < 0)
1857 goto unlock;
1858
1859 if (changed)
1860 err = new_settings(hdev, sk);
1861
1862unlock:
1863 hci_dev_unlock(hdev);
1864 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001865}
1866
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001867static void le_enable_complete(struct hci_dev *hdev, u8 status)
1868{
1869 struct cmd_lookup match = { NULL, hdev };
1870
1871 if (status) {
1872 u8 mgmt_err = mgmt_status(status);
1873
1874 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1875 &mgmt_err);
1876 return;
1877 }
1878
1879 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1880
1881 new_settings(hdev, match.sk);
1882
1883 if (match.sk)
1884 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001885
1886 /* Make sure the controller has a good default for
1887 * advertising data. Restrict the update to when LE
1888 * has actually been enabled. During power on, the
1889 * update in powered_update_hci will take care of it.
1890 */
1891 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1892 struct hci_request req;
1893
1894 hci_dev_lock(hdev);
1895
1896 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001897 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07001898 update_scan_rsp_data(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001899 hci_req_run(&req, NULL);
1900
1901 hci_dev_unlock(hdev);
1902 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001903}
1904
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001905static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001906{
1907 struct mgmt_mode *cp = data;
1908 struct hci_cp_write_le_host_supported hci_cp;
1909 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001910 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001911 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001912 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001913
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001914 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001915
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001916 if (!lmp_le_capable(hdev))
1917 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1918 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001919
Johan Hedberga7e80f22013-01-09 16:05:19 +02001920 if (cp->val != 0x00 && cp->val != 0x01)
1921 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1922 MGMT_STATUS_INVALID_PARAMS);
1923
Johan Hedbergc73eee92013-04-19 18:35:21 +03001924 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001925 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001926 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1927 MGMT_STATUS_REJECTED);
1928
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001929 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001930
1931 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001932 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001933
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001934 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001935 bool changed = false;
1936
1937 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1938 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1939 changed = true;
1940 }
1941
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001942 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1943 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001944 changed = true;
1945 }
1946
Johan Hedberg06199cf2012-02-22 16:37:11 +02001947 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1948 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001949 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001950
1951 if (changed)
1952 err = new_settings(hdev, sk);
1953
Johan Hedberg1de028c2012-02-29 19:55:35 -08001954 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001955 }
1956
Johan Hedberg4375f102013-09-25 13:26:10 +03001957 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1958 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001959 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001960 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001961 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001962 }
1963
1964 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1965 if (!cmd) {
1966 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001967 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001968 }
1969
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001970 hci_req_init(&req, hdev);
1971
Johan Hedberg06199cf2012-02-22 16:37:11 +02001972 memset(&hci_cp, 0, sizeof(hci_cp));
1973
1974 if (val) {
1975 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001976 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001977 } else {
1978 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1979 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001980 }
1981
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001982 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1983 &hci_cp);
1984
1985 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301986 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001987 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001988
Johan Hedberg1de028c2012-02-29 19:55:35 -08001989unlock:
1990 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001991 return err;
1992}
1993
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001994/* This is a helper function to test for pending mgmt commands that can
1995 * cause CoD or EIR HCI commands. We can only allow one such pending
1996 * mgmt command at a time since otherwise we cannot easily track what
1997 * the current values are, will be, and based on that calculate if a new
1998 * HCI command needs to be sent and if yes with what value.
1999 */
2000static bool pending_eir_or_class(struct hci_dev *hdev)
2001{
2002 struct pending_cmd *cmd;
2003
2004 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2005 switch (cmd->opcode) {
2006 case MGMT_OP_ADD_UUID:
2007 case MGMT_OP_REMOVE_UUID:
2008 case MGMT_OP_SET_DEV_CLASS:
2009 case MGMT_OP_SET_POWERED:
2010 return true;
2011 }
2012 }
2013
2014 return false;
2015}
2016
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002017static const u8 bluetooth_base_uuid[] = {
2018 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2019 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2020};
2021
2022static u8 get_uuid_size(const u8 *uuid)
2023{
2024 u32 val;
2025
2026 if (memcmp(uuid, bluetooth_base_uuid, 12))
2027 return 128;
2028
2029 val = get_unaligned_le32(&uuid[12]);
2030 if (val > 0xffff)
2031 return 32;
2032
2033 return 16;
2034}
2035
Johan Hedberg92da6092013-03-15 17:06:55 -05002036static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2037{
2038 struct pending_cmd *cmd;
2039
2040 hci_dev_lock(hdev);
2041
2042 cmd = mgmt_pending_find(mgmt_op, hdev);
2043 if (!cmd)
2044 goto unlock;
2045
2046 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
2047 hdev->dev_class, 3);
2048
2049 mgmt_pending_remove(cmd);
2050
2051unlock:
2052 hci_dev_unlock(hdev);
2053}
2054
2055static void add_uuid_complete(struct hci_dev *hdev, u8 status)
2056{
2057 BT_DBG("status 0x%02x", status);
2058
2059 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2060}
2061
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002062static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002063{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002064 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002065 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002066 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002067 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002068 int err;
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_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002076 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002077 goto failed;
2078 }
2079
Andre Guedes92c4c202012-06-07 19:05:44 -03002080 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002081 if (!uuid) {
2082 err = -ENOMEM;
2083 goto failed;
2084 }
2085
2086 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002087 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002088 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002089
Johan Hedbergde66aa62013-01-27 00:31:27 +02002090 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002091
Johan Hedberg890ea892013-03-15 17:06:52 -05002092 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002093
Johan Hedberg890ea892013-03-15 17:06:52 -05002094 update_class(&req);
2095 update_eir(&req);
2096
Johan Hedberg92da6092013-03-15 17:06:55 -05002097 err = hci_req_run(&req, add_uuid_complete);
2098 if (err < 0) {
2099 if (err != -ENODATA)
2100 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002101
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002102 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002103 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002104 goto failed;
2105 }
2106
2107 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002108 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002109 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002110 goto failed;
2111 }
2112
2113 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002114
2115failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002116 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002117 return err;
2118}
2119
Johan Hedberg24b78d02012-02-23 23:24:30 +02002120static bool enable_service_cache(struct hci_dev *hdev)
2121{
2122 if (!hdev_is_powered(hdev))
2123 return false;
2124
2125 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002126 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2127 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002128 return true;
2129 }
2130
2131 return false;
2132}
2133
Johan Hedberg92da6092013-03-15 17:06:55 -05002134static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
2135{
2136 BT_DBG("status 0x%02x", status);
2137
2138 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2139}
2140
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002141static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002142 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002143{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002144 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002145 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002146 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002147 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 -05002148 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002149 int err, found;
2150
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002151 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002152
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002153 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002154
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002155 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002156 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002157 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002158 goto unlock;
2159 }
2160
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002161 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002162 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002163
Johan Hedberg24b78d02012-02-23 23:24:30 +02002164 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002165 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002166 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002167 goto unlock;
2168 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002169
Johan Hedberg9246a862012-02-23 21:33:16 +02002170 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002171 }
2172
2173 found = 0;
2174
Johan Hedberg056341c2013-01-27 00:31:30 +02002175 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002176 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2177 continue;
2178
2179 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002180 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002181 found++;
2182 }
2183
2184 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002185 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002186 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002187 goto unlock;
2188 }
2189
Johan Hedberg9246a862012-02-23 21:33:16 +02002190update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002191 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002192
Johan Hedberg890ea892013-03-15 17:06:52 -05002193 update_class(&req);
2194 update_eir(&req);
2195
Johan Hedberg92da6092013-03-15 17:06:55 -05002196 err = hci_req_run(&req, remove_uuid_complete);
2197 if (err < 0) {
2198 if (err != -ENODATA)
2199 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002200
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002201 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002202 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002203 goto unlock;
2204 }
2205
2206 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002207 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002208 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002209 goto unlock;
2210 }
2211
2212 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002213
2214unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002215 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002216 return err;
2217}
2218
Johan Hedberg92da6092013-03-15 17:06:55 -05002219static void set_class_complete(struct hci_dev *hdev, u8 status)
2220{
2221 BT_DBG("status 0x%02x", status);
2222
2223 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2224}
2225
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002226static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002227 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002228{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002229 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002230 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002231 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002232 int err;
2233
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002234 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002235
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002236 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002237 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2238 MGMT_STATUS_NOT_SUPPORTED);
2239
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002240 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002241
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002242 if (pending_eir_or_class(hdev)) {
2243 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2244 MGMT_STATUS_BUSY);
2245 goto unlock;
2246 }
2247
2248 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2249 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2250 MGMT_STATUS_INVALID_PARAMS);
2251 goto unlock;
2252 }
2253
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002254 hdev->major_class = cp->major;
2255 hdev->minor_class = cp->minor;
2256
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002257 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002258 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002259 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002260 goto unlock;
2261 }
2262
Johan Hedberg890ea892013-03-15 17:06:52 -05002263 hci_req_init(&req, hdev);
2264
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002265 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002266 hci_dev_unlock(hdev);
2267 cancel_delayed_work_sync(&hdev->service_cache);
2268 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002269 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002270 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002271
Johan Hedberg890ea892013-03-15 17:06:52 -05002272 update_class(&req);
2273
Johan Hedberg92da6092013-03-15 17:06:55 -05002274 err = hci_req_run(&req, set_class_complete);
2275 if (err < 0) {
2276 if (err != -ENODATA)
2277 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002278
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002279 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002280 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002281 goto unlock;
2282 }
2283
2284 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002285 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002286 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002287 goto unlock;
2288 }
2289
2290 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002291
Johan Hedbergb5235a62012-02-21 14:32:24 +02002292unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002293 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002294 return err;
2295}
2296
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002297static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002298 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002299{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002300 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002301 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002302 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002303 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002304
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002305 BT_DBG("request for %s", hdev->name);
2306
2307 if (!lmp_bredr_capable(hdev))
2308 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2309 MGMT_STATUS_NOT_SUPPORTED);
2310
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002311 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002312
Johan Hedberg86742e12011-11-07 23:13:38 +02002313 expected_len = sizeof(*cp) + key_count *
2314 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002315 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002316 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002317 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002318 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002319 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002320 }
2321
Johan Hedberg4ae14302013-01-20 14:27:13 +02002322 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2323 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2324 MGMT_STATUS_INVALID_PARAMS);
2325
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002326 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002327 key_count);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002328
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002329 for (i = 0; i < key_count; i++) {
2330 struct mgmt_link_key_info *key = &cp->keys[i];
2331
Marcel Holtmann8e991132014-01-10 02:07:25 -08002332 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002333 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2334 MGMT_STATUS_INVALID_PARAMS);
2335 }
2336
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002337 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002338
2339 hci_link_keys_clear(hdev);
2340
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002341 if (cp->debug_keys)
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002342 changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002343 else
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002344 changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
2345
2346 if (changed)
2347 new_settings(hdev, NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002348
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002349 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002350 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002351
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002352 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002353 key->type, key->pin_len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002354 }
2355
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002356 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002357
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002358 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002359
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002360 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002361}
2362
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002363static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002364 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002365{
2366 struct mgmt_ev_device_unpaired ev;
2367
2368 bacpy(&ev.addr.bdaddr, bdaddr);
2369 ev.addr.type = addr_type;
2370
2371 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002372 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002373}
2374
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002375static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002376 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002377{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002378 struct mgmt_cp_unpair_device *cp = data;
2379 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002380 struct hci_cp_disconnect dc;
2381 struct pending_cmd *cmd;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002382 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002383 int err;
2384
Johan Hedberga8a1d192011-11-10 15:54:38 +02002385 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002386 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2387 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002388
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002389 if (!bdaddr_type_is_valid(cp->addr.type))
2390 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2391 MGMT_STATUS_INVALID_PARAMS,
2392 &rp, sizeof(rp));
2393
Johan Hedberg118da702013-01-20 14:27:20 +02002394 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2395 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2396 MGMT_STATUS_INVALID_PARAMS,
2397 &rp, sizeof(rp));
2398
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002399 hci_dev_lock(hdev);
2400
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002401 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002402 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002403 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002404 goto unlock;
2405 }
2406
Johan Hedberge0b2b272014-02-18 17:14:31 +02002407 if (cp->addr.type == BDADDR_BREDR) {
Johan Hedberg124f6e32012-02-09 13:50:12 +02002408 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedberge0b2b272014-02-18 17:14:31 +02002409 } else {
2410 u8 addr_type;
2411
2412 if (cp->addr.type == BDADDR_LE_PUBLIC)
2413 addr_type = ADDR_LE_DEV_PUBLIC;
2414 else
2415 addr_type = ADDR_LE_DEV_RANDOM;
2416
Johan Hedberga7ec7332014-02-18 17:14:35 +02002417 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2418
Andre Guedesa9b0a042014-02-26 20:21:52 -03002419 hci_conn_params_del(hdev, &cp->addr.bdaddr, addr_type);
2420
Johan Hedberge0b2b272014-02-18 17:14:31 +02002421 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
2422 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002423
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002424 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002425 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002426 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002427 goto unlock;
2428 }
2429
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002430 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002431 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002432 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002433 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002434 else
2435 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002436 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002437 } else {
2438 conn = NULL;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002439 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002440
Johan Hedberga8a1d192011-11-10 15:54:38 +02002441 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002442 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002443 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002444 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002445 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002446 }
2447
Johan Hedberg124f6e32012-02-09 13:50:12 +02002448 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002449 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002450 if (!cmd) {
2451 err = -ENOMEM;
2452 goto unlock;
2453 }
2454
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002455 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002456 dc.reason = 0x13; /* Remote User Terminated Connection */
2457 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2458 if (err < 0)
2459 mgmt_pending_remove(cmd);
2460
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002461unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002462 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002463 return err;
2464}
2465
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002466static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002467 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002468{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002469 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002470 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002471 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002472 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002473 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002474 int err;
2475
2476 BT_DBG("");
2477
Johan Hedberg06a63b12013-01-20 14:27:21 +02002478 memset(&rp, 0, sizeof(rp));
2479 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2480 rp.addr.type = cp->addr.type;
2481
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002482 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002483 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2484 MGMT_STATUS_INVALID_PARAMS,
2485 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002486
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002487 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002488
2489 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002490 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2491 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002492 goto failed;
2493 }
2494
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002495 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002496 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2497 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002498 goto failed;
2499 }
2500
Andre Guedes591f47f2012-04-24 21:02:49 -03002501 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002502 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2503 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002504 else
2505 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002506
Vishal Agarwalf9607272012-06-13 05:32:43 +05302507 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002508 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2509 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002510 goto failed;
2511 }
2512
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002513 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002514 if (!cmd) {
2515 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002516 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002517 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002518
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002519 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002520 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002521
2522 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2523 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002524 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002525
2526failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002527 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002528 return err;
2529}
2530
Andre Guedes57c14772012-04-24 21:02:50 -03002531static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002532{
2533 switch (link_type) {
2534 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002535 switch (addr_type) {
2536 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002537 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002538
Johan Hedberg48264f02011-11-09 13:58:58 +02002539 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002540 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002541 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002542 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002543
Johan Hedberg4c659c32011-11-07 23:13:39 +02002544 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002545 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002546 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002547 }
2548}
2549
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002550static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2551 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002552{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002553 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002554 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002555 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002556 int err;
2557 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002558
2559 BT_DBG("");
2560
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002561 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002562
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002563 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002564 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002565 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002566 goto unlock;
2567 }
2568
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002569 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002570 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2571 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002572 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002573 }
2574
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002575 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002576 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002577 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002578 err = -ENOMEM;
2579 goto unlock;
2580 }
2581
Johan Hedberg2784eb42011-01-21 13:56:35 +02002582 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002583 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002584 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2585 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002586 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002587 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002588 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002589 continue;
2590 i++;
2591 }
2592
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002593 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002594
Johan Hedberg4c659c32011-11-07 23:13:39 +02002595 /* Recalculate length in case of filtered SCO connections, etc */
2596 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002597
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002598 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002599 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002600
Johan Hedberga38528f2011-01-22 06:46:43 +02002601 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002602
2603unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002604 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002605 return err;
2606}
2607
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002608static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002609 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002610{
2611 struct pending_cmd *cmd;
2612 int err;
2613
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002614 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002615 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002616 if (!cmd)
2617 return -ENOMEM;
2618
Johan Hedbergd8457692012-02-17 14:24:57 +02002619 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002620 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002621 if (err < 0)
2622 mgmt_pending_remove(cmd);
2623
2624 return err;
2625}
2626
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002627static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002628 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002629{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002630 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002631 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002632 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002633 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002634 int err;
2635
2636 BT_DBG("");
2637
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002638 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002639
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002640 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002641 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002642 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002643 goto failed;
2644 }
2645
Johan Hedbergd8457692012-02-17 14:24:57 +02002646 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002647 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002648 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002649 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002650 goto failed;
2651 }
2652
2653 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002654 struct mgmt_cp_pin_code_neg_reply ncp;
2655
2656 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002657
2658 BT_ERR("PIN code is not 16 bytes long");
2659
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002660 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002661 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002662 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002663 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002664
2665 goto failed;
2666 }
2667
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002668 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002669 if (!cmd) {
2670 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002671 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002672 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002673
Johan Hedbergd8457692012-02-17 14:24:57 +02002674 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002675 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002676 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002677
2678 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2679 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002680 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002681
2682failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002683 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002684 return err;
2685}
2686
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002687static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2688 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002689{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002690 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002691
2692 BT_DBG("");
2693
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002694 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002695
2696 hdev->io_capability = cp->io_capability;
2697
2698 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002699 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002700
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002701 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002702
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002703 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2704 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002705}
2706
Gustavo Padovan6039aa732012-05-23 04:04:18 -03002707static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002708{
2709 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002710 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002711
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002712 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002713 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2714 continue;
2715
Johan Hedberge9a416b2011-02-19 12:05:56 -03002716 if (cmd->user_data != conn)
2717 continue;
2718
2719 return cmd;
2720 }
2721
2722 return NULL;
2723}
2724
2725static void pairing_complete(struct pending_cmd *cmd, u8 status)
2726{
2727 struct mgmt_rp_pair_device rp;
2728 struct hci_conn *conn = cmd->user_data;
2729
Johan Hedbergba4e5642011-11-11 00:07:34 +02002730 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002731 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002732
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002733 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002734 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002735
2736 /* So we don't get further callbacks for this connection */
2737 conn->connect_cfm_cb = NULL;
2738 conn->security_cfm_cb = NULL;
2739 conn->disconn_cfm_cb = NULL;
2740
David Herrmann76a68ba2013-04-06 20:28:37 +02002741 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002742
Johan Hedberga664b5b2011-02-19 12:06:02 -03002743 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002744}
2745
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002746void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2747{
2748 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
2749 struct pending_cmd *cmd;
2750
2751 cmd = find_pairing(conn);
2752 if (cmd)
2753 pairing_complete(cmd, status);
2754}
2755
Johan Hedberge9a416b2011-02-19 12:05:56 -03002756static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2757{
2758 struct pending_cmd *cmd;
2759
2760 BT_DBG("status %u", status);
2761
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002762 cmd = find_pairing(conn);
2763 if (!cmd)
2764 BT_DBG("Unable to find a pending command");
2765 else
Johan Hedberge2113262012-02-18 15:20:03 +02002766 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002767}
2768
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002769static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302770{
2771 struct pending_cmd *cmd;
2772
2773 BT_DBG("status %u", status);
2774
2775 if (!status)
2776 return;
2777
2778 cmd = find_pairing(conn);
2779 if (!cmd)
2780 BT_DBG("Unable to find a pending command");
2781 else
2782 pairing_complete(cmd, mgmt_status(status));
2783}
2784
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002785static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002786 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002787{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002788 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002789 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002790 struct pending_cmd *cmd;
2791 u8 sec_level, auth_type;
2792 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002793 int err;
2794
2795 BT_DBG("");
2796
Szymon Jancf950a30e2013-01-18 12:48:07 +01002797 memset(&rp, 0, sizeof(rp));
2798 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2799 rp.addr.type = cp->addr.type;
2800
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002801 if (!bdaddr_type_is_valid(cp->addr.type))
2802 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2803 MGMT_STATUS_INVALID_PARAMS,
2804 &rp, sizeof(rp));
2805
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002806 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002807
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002808 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002809 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2810 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002811 goto unlock;
2812 }
2813
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002814 sec_level = BT_SECURITY_MEDIUM;
2815 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002816 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002817 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002818 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002819
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002820 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002821 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2822 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002823 } else {
2824 u8 addr_type;
2825
2826 /* Convert from L2CAP channel address type to HCI address type
2827 */
2828 if (cp->addr.type == BDADDR_LE_PUBLIC)
2829 addr_type = ADDR_LE_DEV_PUBLIC;
2830 else
2831 addr_type = ADDR_LE_DEV_RANDOM;
2832
2833 conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type,
Andre Guedes04a6c582014-02-26 20:21:44 -03002834 sec_level, auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002835 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002836
Ville Tervo30e76272011-02-22 16:10:53 -03002837 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002838 int status;
2839
2840 if (PTR_ERR(conn) == -EBUSY)
2841 status = MGMT_STATUS_BUSY;
2842 else
2843 status = MGMT_STATUS_CONNECT_FAILED;
2844
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002845 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002846 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002847 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002848 goto unlock;
2849 }
2850
2851 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002852 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002853 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002854 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002855 goto unlock;
2856 }
2857
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002858 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002859 if (!cmd) {
2860 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002861 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002862 goto unlock;
2863 }
2864
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002865 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002866 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002867 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002868 conn->security_cfm_cb = pairing_complete_cb;
2869 conn->disconn_cfm_cb = pairing_complete_cb;
2870 } else {
2871 conn->connect_cfm_cb = le_pairing_complete_cb;
2872 conn->security_cfm_cb = le_pairing_complete_cb;
2873 conn->disconn_cfm_cb = le_pairing_complete_cb;
2874 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002875
Johan Hedberge9a416b2011-02-19 12:05:56 -03002876 conn->io_capability = cp->io_cap;
2877 cmd->user_data = conn;
2878
2879 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002880 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002881 pairing_complete(cmd, 0);
2882
2883 err = 0;
2884
2885unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002886 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002887 return err;
2888}
2889
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002890static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2891 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002892{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002893 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002894 struct pending_cmd *cmd;
2895 struct hci_conn *conn;
2896 int err;
2897
2898 BT_DBG("");
2899
Johan Hedberg28424702012-02-02 04:02:29 +02002900 hci_dev_lock(hdev);
2901
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002902 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002903 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002904 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002905 goto unlock;
2906 }
2907
Johan Hedberg28424702012-02-02 04:02:29 +02002908 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2909 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002910 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002911 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002912 goto unlock;
2913 }
2914
2915 conn = cmd->user_data;
2916
2917 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002918 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002919 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002920 goto unlock;
2921 }
2922
2923 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2924
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002925 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002926 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002927unlock:
2928 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002929 return err;
2930}
2931
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002932static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002933 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002934 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002935{
Johan Hedberga5c29682011-02-19 12:05:57 -03002936 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002937 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002938 int err;
2939
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002940 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002941
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002942 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002943 err = cmd_complete(sk, hdev->id, mgmt_op,
2944 MGMT_STATUS_NOT_POWERED, addr,
2945 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002946 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002947 }
2948
Johan Hedberg1707c602013-03-15 17:07:15 -05002949 if (addr->type == BDADDR_BREDR)
2950 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002951 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002952 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002953
Johan Hedberg272d90d2012-02-09 15:26:12 +02002954 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002955 err = cmd_complete(sk, hdev->id, mgmt_op,
2956 MGMT_STATUS_NOT_CONNECTED, addr,
2957 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002958 goto done;
2959 }
2960
Johan Hedberg1707c602013-03-15 17:07:15 -05002961 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002962 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002963 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002964
Brian Gix5fe57d92011-12-21 16:12:13 -08002965 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002966 err = cmd_complete(sk, hdev->id, mgmt_op,
2967 MGMT_STATUS_SUCCESS, addr,
2968 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002969 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002970 err = cmd_complete(sk, hdev->id, mgmt_op,
2971 MGMT_STATUS_FAILED, addr,
2972 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002973
Brian Gix47c15e22011-11-16 13:53:14 -08002974 goto done;
2975 }
2976
Johan Hedberg1707c602013-03-15 17:07:15 -05002977 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002978 if (!cmd) {
2979 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002980 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002981 }
2982
Brian Gix0df4c182011-11-16 13:53:13 -08002983 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002984 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2985 struct hci_cp_user_passkey_reply cp;
2986
Johan Hedberg1707c602013-03-15 17:07:15 -05002987 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002988 cp.passkey = passkey;
2989 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2990 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002991 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2992 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002993
Johan Hedberga664b5b2011-02-19 12:06:02 -03002994 if (err < 0)
2995 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002996
Brian Gix0df4c182011-11-16 13:53:13 -08002997done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002998 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002999 return err;
3000}
3001
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303002static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3003 void *data, u16 len)
3004{
3005 struct mgmt_cp_pin_code_neg_reply *cp = data;
3006
3007 BT_DBG("");
3008
Johan Hedberg1707c602013-03-15 17:07:15 -05003009 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303010 MGMT_OP_PIN_CODE_NEG_REPLY,
3011 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3012}
3013
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003014static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3015 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003016{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003017 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003018
3019 BT_DBG("");
3020
3021 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003022 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003023 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003024
Johan Hedberg1707c602013-03-15 17:07:15 -05003025 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003026 MGMT_OP_USER_CONFIRM_REPLY,
3027 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003028}
3029
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003030static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003031 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003032{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003033 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003034
3035 BT_DBG("");
3036
Johan Hedberg1707c602013-03-15 17:07:15 -05003037 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003038 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3039 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003040}
3041
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003042static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3043 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003044{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003045 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003046
3047 BT_DBG("");
3048
Johan Hedberg1707c602013-03-15 17:07:15 -05003049 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003050 MGMT_OP_USER_PASSKEY_REPLY,
3051 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003052}
3053
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003054static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003055 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003056{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003057 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003058
3059 BT_DBG("");
3060
Johan Hedberg1707c602013-03-15 17:07:15 -05003061 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003062 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3063 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003064}
3065
Johan Hedberg13928972013-03-15 17:07:00 -05003066static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003067{
Johan Hedberg13928972013-03-15 17:07:00 -05003068 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003069 struct hci_cp_write_local_name cp;
3070
Johan Hedberg13928972013-03-15 17:07:00 -05003071 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003072
Johan Hedberg890ea892013-03-15 17:06:52 -05003073 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003074}
3075
Johan Hedberg13928972013-03-15 17:07:00 -05003076static void set_name_complete(struct hci_dev *hdev, u8 status)
3077{
3078 struct mgmt_cp_set_local_name *cp;
3079 struct pending_cmd *cmd;
3080
3081 BT_DBG("status 0x%02x", status);
3082
3083 hci_dev_lock(hdev);
3084
3085 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
3086 if (!cmd)
3087 goto unlock;
3088
3089 cp = cmd->param;
3090
3091 if (status)
3092 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3093 mgmt_status(status));
3094 else
3095 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3096 cp, sizeof(*cp));
3097
3098 mgmt_pending_remove(cmd);
3099
3100unlock:
3101 hci_dev_unlock(hdev);
3102}
3103
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003104static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003105 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003106{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003107 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003108 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003109 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003110 int err;
3111
3112 BT_DBG("");
3113
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003114 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003115
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003116 /* If the old values are the same as the new ones just return a
3117 * direct command complete event.
3118 */
3119 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3120 !memcmp(hdev->short_name, cp->short_name,
3121 sizeof(hdev->short_name))) {
3122 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3123 data, len);
3124 goto failed;
3125 }
3126
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003127 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003128
Johan Hedbergb5235a62012-02-21 14:32:24 +02003129 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003130 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003131
3132 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003133 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003134 if (err < 0)
3135 goto failed;
3136
3137 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003138 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003139
Johan Hedbergb5235a62012-02-21 14:32:24 +02003140 goto failed;
3141 }
3142
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003143 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003144 if (!cmd) {
3145 err = -ENOMEM;
3146 goto failed;
3147 }
3148
Johan Hedberg13928972013-03-15 17:07:00 -05003149 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3150
Johan Hedberg890ea892013-03-15 17:06:52 -05003151 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003152
3153 if (lmp_bredr_capable(hdev)) {
3154 update_name(&req);
3155 update_eir(&req);
3156 }
3157
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003158 /* The name is stored in the scan response data and so
3159 * no need to udpate the advertising data here.
3160 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003161 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003162 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003163
Johan Hedberg13928972013-03-15 17:07:00 -05003164 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003165 if (err < 0)
3166 mgmt_pending_remove(cmd);
3167
3168failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003169 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003170 return err;
3171}
3172
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003173static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003174 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003175{
Szymon Jancc35938b2011-03-22 13:12:21 +01003176 struct pending_cmd *cmd;
3177 int err;
3178
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003179 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003180
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003181 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003182
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003183 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003184 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003185 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003186 goto unlock;
3187 }
3188
Andre Guedes9a1a1992012-07-24 15:03:48 -03003189 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003190 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003191 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003192 goto unlock;
3193 }
3194
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003195 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003196 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003197 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003198 goto unlock;
3199 }
3200
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003201 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003202 if (!cmd) {
3203 err = -ENOMEM;
3204 goto unlock;
3205 }
3206
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003207 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
3208 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
3209 0, NULL);
3210 else
3211 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3212
Szymon Jancc35938b2011-03-22 13:12:21 +01003213 if (err < 0)
3214 mgmt_pending_remove(cmd);
3215
3216unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003217 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003218 return err;
3219}
3220
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003221static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003222 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003223{
Szymon Janc2763eda2011-03-22 13:12:22 +01003224 int err;
3225
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003226 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003227
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003228 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003229
Marcel Holtmannec109112014-01-10 02:07:30 -08003230 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3231 struct mgmt_cp_add_remote_oob_data *cp = data;
3232 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003233
Marcel Holtmannec109112014-01-10 02:07:30 -08003234 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
3235 cp->hash, cp->randomizer);
3236 if (err < 0)
3237 status = MGMT_STATUS_FAILED;
3238 else
3239 status = MGMT_STATUS_SUCCESS;
3240
3241 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3242 status, &cp->addr, sizeof(cp->addr));
3243 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3244 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
3245 u8 status;
3246
3247 err = hci_add_remote_oob_ext_data(hdev, &cp->addr.bdaddr,
3248 cp->hash192,
3249 cp->randomizer192,
3250 cp->hash256,
3251 cp->randomizer256);
3252 if (err < 0)
3253 status = MGMT_STATUS_FAILED;
3254 else
3255 status = MGMT_STATUS_SUCCESS;
3256
3257 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3258 status, &cp->addr, sizeof(cp->addr));
3259 } else {
3260 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
3261 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3262 MGMT_STATUS_INVALID_PARAMS);
3263 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003264
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003265 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003266 return err;
3267}
3268
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003269static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003270 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003271{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003272 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003273 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003274 int err;
3275
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003276 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003277
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003278 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003279
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003280 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003281 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003282 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003283 else
Szymon Janca6785be2012-12-13 15:11:21 +01003284 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003285
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003286 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003287 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003288
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003289 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003290 return err;
3291}
3292
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003293static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3294{
3295 struct pending_cmd *cmd;
3296 u8 type;
3297 int err;
3298
3299 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3300
3301 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3302 if (!cmd)
3303 return -ENOENT;
3304
3305 type = hdev->discovery.type;
3306
3307 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3308 &type, sizeof(type));
3309 mgmt_pending_remove(cmd);
3310
3311 return err;
3312}
3313
Andre Guedes7c307722013-04-30 15:29:28 -03003314static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3315{
3316 BT_DBG("status %d", status);
3317
3318 if (status) {
3319 hci_dev_lock(hdev);
3320 mgmt_start_discovery_failed(hdev, status);
3321 hci_dev_unlock(hdev);
3322 return;
3323 }
3324
3325 hci_dev_lock(hdev);
3326 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3327 hci_dev_unlock(hdev);
3328
3329 switch (hdev->discovery.type) {
3330 case DISCOV_TYPE_LE:
3331 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003332 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003333 break;
3334
3335 case DISCOV_TYPE_INTERLEAVED:
3336 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003337 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003338 break;
3339
3340 case DISCOV_TYPE_BREDR:
3341 break;
3342
3343 default:
3344 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3345 }
3346}
3347
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003348static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003349 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003350{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003351 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003352 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003353 struct hci_cp_le_set_scan_param param_cp;
3354 struct hci_cp_le_set_scan_enable enable_cp;
3355 struct hci_cp_inquiry inq_cp;
3356 struct hci_request req;
3357 /* General inquiry access code (GIAC) */
3358 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedbergd9483942014-02-23 19:42:24 +02003359 u8 status, own_addr_type;
Johan Hedberg14a53662011-04-27 10:29:56 -04003360 int err;
3361
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003362 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003363
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003364 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003365
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003366 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003367 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003368 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003369 goto failed;
3370 }
3371
Andre Guedes642be6c2012-03-21 00:03:37 -03003372 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3373 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3374 MGMT_STATUS_BUSY);
3375 goto failed;
3376 }
3377
Johan Hedbergff9ef572012-01-04 14:23:45 +02003378 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003379 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003380 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003381 goto failed;
3382 }
3383
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003384 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003385 if (!cmd) {
3386 err = -ENOMEM;
3387 goto failed;
3388 }
3389
Andre Guedes4aab14e2012-02-17 20:39:36 -03003390 hdev->discovery.type = cp->type;
3391
Andre Guedes7c307722013-04-30 15:29:28 -03003392 hci_req_init(&req, hdev);
3393
Andre Guedes4aab14e2012-02-17 20:39:36 -03003394 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003395 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003396 status = mgmt_bredr_support(hdev);
3397 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003398 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003399 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003400 mgmt_pending_remove(cmd);
3401 goto failed;
3402 }
3403
Andre Guedes7c307722013-04-30 15:29:28 -03003404 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3405 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3406 MGMT_STATUS_BUSY);
3407 mgmt_pending_remove(cmd);
3408 goto failed;
3409 }
3410
3411 hci_inquiry_cache_flush(hdev);
3412
3413 memset(&inq_cp, 0, sizeof(inq_cp));
3414 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003415 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003416 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003417 break;
3418
3419 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003420 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003421 status = mgmt_le_support(hdev);
3422 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003423 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003424 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003425 mgmt_pending_remove(cmd);
3426 goto failed;
3427 }
3428
Andre Guedes7c307722013-04-30 15:29:28 -03003429 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003430 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003431 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3432 MGMT_STATUS_NOT_SUPPORTED);
3433 mgmt_pending_remove(cmd);
3434 goto failed;
3435 }
3436
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003437 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003438 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3439 MGMT_STATUS_REJECTED);
3440 mgmt_pending_remove(cmd);
3441 goto failed;
3442 }
3443
Andre Guedesc54c3862014-02-26 20:21:50 -03003444 /* If controller is scanning, it means the background scanning
3445 * is running. Thus, we should temporarily stop it in order to
3446 * set the discovery scanning parameters.
3447 */
3448 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
3449 hci_req_add_le_scan_disable(&req);
Andre Guedes7c307722013-04-30 15:29:28 -03003450
3451 memset(&param_cp, 0, sizeof(param_cp));
Johan Hedbergd9483942014-02-23 19:42:24 +02003452
Marcel Holtmann94b1fc92014-02-23 20:25:54 -08003453 /* All active scans will be done with either a resolvable
3454 * private address (when privacy feature has been enabled)
3455 * or unresolvable private address.
3456 */
3457 err = hci_update_random_address(&req, true, &own_addr_type);
Johan Hedbergd9483942014-02-23 19:42:24 +02003458 if (err < 0) {
3459 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3460 MGMT_STATUS_FAILED);
3461 mgmt_pending_remove(cmd);
3462 goto failed;
3463 }
3464
Andre Guedes7c307722013-04-30 15:29:28 -03003465 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003466 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3467 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Johan Hedbergd9483942014-02-23 19:42:24 +02003468 param_cp.own_address_type = own_addr_type;
Andre Guedes7c307722013-04-30 15:29:28 -03003469 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3470 &param_cp);
3471
3472 memset(&enable_cp, 0, sizeof(enable_cp));
3473 enable_cp.enable = LE_SCAN_ENABLE;
3474 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3475 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3476 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003477 break;
3478
Andre Guedesf39799f2012-02-17 20:39:35 -03003479 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003480 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3481 MGMT_STATUS_INVALID_PARAMS);
3482 mgmt_pending_remove(cmd);
3483 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003484 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003485
Andre Guedes7c307722013-04-30 15:29:28 -03003486 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003487 if (err < 0)
3488 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003489 else
3490 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003491
3492failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003493 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003494 return err;
3495}
3496
Andre Guedes1183fdc2013-04-30 15:29:35 -03003497static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3498{
3499 struct pending_cmd *cmd;
3500 int err;
3501
3502 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3503 if (!cmd)
3504 return -ENOENT;
3505
3506 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3507 &hdev->discovery.type, sizeof(hdev->discovery.type));
3508 mgmt_pending_remove(cmd);
3509
3510 return err;
3511}
3512
Andre Guedes0e05bba2013-04-30 15:29:33 -03003513static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3514{
3515 BT_DBG("status %d", status);
3516
3517 hci_dev_lock(hdev);
3518
3519 if (status) {
3520 mgmt_stop_discovery_failed(hdev, status);
3521 goto unlock;
3522 }
3523
3524 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3525
3526unlock:
3527 hci_dev_unlock(hdev);
3528}
3529
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003530static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003531 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003532{
Johan Hedbergd9306502012-02-20 23:25:18 +02003533 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003534 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003535 struct hci_cp_remote_name_req_cancel cp;
3536 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003537 struct hci_request req;
Johan Hedberg14a53662011-04-27 10:29:56 -04003538 int err;
3539
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003540 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003541
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003542 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003543
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003544 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003545 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003546 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3547 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003548 goto unlock;
3549 }
3550
3551 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003552 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003553 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3554 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003555 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003556 }
3557
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003558 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003559 if (!cmd) {
3560 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003561 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003562 }
3563
Andre Guedes0e05bba2013-04-30 15:29:33 -03003564 hci_req_init(&req, hdev);
3565
Andre Guedese0d9727e2012-03-20 15:15:36 -03003566 switch (hdev->discovery.state) {
3567 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003568 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3569 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3570 } else {
3571 cancel_delayed_work(&hdev->le_scan_disable);
3572
Andre Guedesb1efcc22014-02-26 20:21:40 -03003573 hci_req_add_le_scan_disable(&req);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003574 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003575
Andre Guedese0d9727e2012-03-20 15:15:36 -03003576 break;
3577
3578 case DISCOVERY_RESOLVING:
3579 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003580 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003581 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003582 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003583 err = cmd_complete(sk, hdev->id,
3584 MGMT_OP_STOP_DISCOVERY, 0,
3585 &mgmt_cp->type,
3586 sizeof(mgmt_cp->type));
3587 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3588 goto unlock;
3589 }
3590
3591 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003592 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3593 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003594
3595 break;
3596
3597 default:
3598 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003599
3600 mgmt_pending_remove(cmd);
3601 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3602 MGMT_STATUS_FAILED, &mgmt_cp->type,
3603 sizeof(mgmt_cp->type));
3604 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003605 }
3606
Andre Guedes0e05bba2013-04-30 15:29:33 -03003607 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003608 if (err < 0)
3609 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003610 else
3611 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003612
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003613unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003614 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003615 return err;
3616}
3617
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003618static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003619 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003620{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003621 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003622 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003623 int err;
3624
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003625 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003626
Johan Hedberg561aafb2012-01-04 13:31:59 +02003627 hci_dev_lock(hdev);
3628
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003629 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003630 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003631 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003632 goto failed;
3633 }
3634
Johan Hedberga198e7b2012-02-17 14:27:06 +02003635 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003636 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003637 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003638 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003639 goto failed;
3640 }
3641
3642 if (cp->name_known) {
3643 e->name_state = NAME_KNOWN;
3644 list_del(&e->list);
3645 } else {
3646 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003647 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003648 }
3649
Johan Hedberge3846622013-01-09 15:29:33 +02003650 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3651 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003652
3653failed:
3654 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003655 return err;
3656}
3657
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003658static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003659 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003660{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003661 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003662 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003663 int err;
3664
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003665 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003666
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003667 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003668 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3669 MGMT_STATUS_INVALID_PARAMS,
3670 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003671
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003672 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003673
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003674 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003675 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003676 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003677 else
Szymon Janca6785be2012-12-13 15:11:21 +01003678 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003679
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003680 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003681 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003682
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003683 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003684
3685 return err;
3686}
3687
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003688static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003689 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003690{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003691 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003692 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003693 int err;
3694
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003695 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003696
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003697 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003698 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3699 MGMT_STATUS_INVALID_PARAMS,
3700 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003701
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003702 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003703
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003704 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003705 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003706 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003707 else
Szymon Janca6785be2012-12-13 15:11:21 +01003708 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003709
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003710 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003711 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003712
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003713 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003714
3715 return err;
3716}
3717
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003718static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3719 u16 len)
3720{
3721 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003722 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003723 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003724 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003725
3726 BT_DBG("%s", hdev->name);
3727
Szymon Jancc72d4b82012-03-16 16:02:57 +01003728 source = __le16_to_cpu(cp->source);
3729
3730 if (source > 0x0002)
3731 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3732 MGMT_STATUS_INVALID_PARAMS);
3733
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003734 hci_dev_lock(hdev);
3735
Szymon Jancc72d4b82012-03-16 16:02:57 +01003736 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003737 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3738 hdev->devid_product = __le16_to_cpu(cp->product);
3739 hdev->devid_version = __le16_to_cpu(cp->version);
3740
3741 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3742
Johan Hedberg890ea892013-03-15 17:06:52 -05003743 hci_req_init(&req, hdev);
3744 update_eir(&req);
3745 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003746
3747 hci_dev_unlock(hdev);
3748
3749 return err;
3750}
3751
Johan Hedberg4375f102013-09-25 13:26:10 +03003752static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3753{
3754 struct cmd_lookup match = { NULL, hdev };
3755
3756 if (status) {
3757 u8 mgmt_err = mgmt_status(status);
3758
3759 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3760 cmd_status_rsp, &mgmt_err);
3761 return;
3762 }
3763
3764 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3765 &match);
3766
3767 new_settings(hdev, match.sk);
3768
3769 if (match.sk)
3770 sock_put(match.sk);
3771}
3772
Marcel Holtmann21b51872013-10-10 09:47:53 -07003773static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3774 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003775{
3776 struct mgmt_mode *cp = data;
3777 struct pending_cmd *cmd;
3778 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003779 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003780 int err;
3781
3782 BT_DBG("request for %s", hdev->name);
3783
Johan Hedberge6fe7982013-10-02 15:45:22 +03003784 status = mgmt_le_support(hdev);
3785 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003786 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003787 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003788
3789 if (cp->val != 0x00 && cp->val != 0x01)
3790 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3791 MGMT_STATUS_INVALID_PARAMS);
3792
3793 hci_dev_lock(hdev);
3794
3795 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003796 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003797
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003798 /* The following conditions are ones which mean that we should
3799 * not do any HCI communication but directly send a mgmt
3800 * response to user space (after toggling the flag if
3801 * necessary).
3802 */
3803 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003804 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003805 bool changed = false;
3806
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003807 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3808 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003809 changed = true;
3810 }
3811
3812 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3813 if (err < 0)
3814 goto unlock;
3815
3816 if (changed)
3817 err = new_settings(hdev, sk);
3818
3819 goto unlock;
3820 }
3821
3822 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3823 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3824 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3825 MGMT_STATUS_BUSY);
3826 goto unlock;
3827 }
3828
3829 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3830 if (!cmd) {
3831 err = -ENOMEM;
3832 goto unlock;
3833 }
3834
3835 hci_req_init(&req, hdev);
3836
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003837 if (val)
3838 enable_advertising(&req);
3839 else
3840 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003841
3842 err = hci_req_run(&req, set_advertising_complete);
3843 if (err < 0)
3844 mgmt_pending_remove(cmd);
3845
3846unlock:
3847 hci_dev_unlock(hdev);
3848 return err;
3849}
3850
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003851static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3852 void *data, u16 len)
3853{
3854 struct mgmt_cp_set_static_address *cp = data;
3855 int err;
3856
3857 BT_DBG("%s", hdev->name);
3858
Marcel Holtmann62af4442013-10-02 22:10:32 -07003859 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003860 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003861 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003862
3863 if (hdev_is_powered(hdev))
3864 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3865 MGMT_STATUS_REJECTED);
3866
3867 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3868 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3869 return cmd_status(sk, hdev->id,
3870 MGMT_OP_SET_STATIC_ADDRESS,
3871 MGMT_STATUS_INVALID_PARAMS);
3872
3873 /* Two most significant bits shall be set */
3874 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3875 return cmd_status(sk, hdev->id,
3876 MGMT_OP_SET_STATIC_ADDRESS,
3877 MGMT_STATUS_INVALID_PARAMS);
3878 }
3879
3880 hci_dev_lock(hdev);
3881
3882 bacpy(&hdev->static_addr, &cp->bdaddr);
3883
3884 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3885
3886 hci_dev_unlock(hdev);
3887
3888 return err;
3889}
3890
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003891static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3892 void *data, u16 len)
3893{
3894 struct mgmt_cp_set_scan_params *cp = data;
3895 __u16 interval, window;
3896 int err;
3897
3898 BT_DBG("%s", hdev->name);
3899
3900 if (!lmp_le_capable(hdev))
3901 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3902 MGMT_STATUS_NOT_SUPPORTED);
3903
3904 interval = __le16_to_cpu(cp->interval);
3905
3906 if (interval < 0x0004 || interval > 0x4000)
3907 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3908 MGMT_STATUS_INVALID_PARAMS);
3909
3910 window = __le16_to_cpu(cp->window);
3911
3912 if (window < 0x0004 || window > 0x4000)
3913 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3914 MGMT_STATUS_INVALID_PARAMS);
3915
Marcel Holtmann899e1072013-10-14 09:55:32 -07003916 if (window > interval)
3917 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3918 MGMT_STATUS_INVALID_PARAMS);
3919
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003920 hci_dev_lock(hdev);
3921
3922 hdev->le_scan_interval = interval;
3923 hdev->le_scan_window = window;
3924
3925 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3926
Andre Guedesdd2ef8e2014-02-26 20:21:56 -03003927 /* If background scan is running, restart it so new parameters are
3928 * loaded.
3929 */
3930 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags) &&
3931 hdev->discovery.state == DISCOVERY_STOPPED) {
3932 struct hci_request req;
3933
3934 hci_req_init(&req, hdev);
3935
3936 hci_req_add_le_scan_disable(&req);
3937 hci_req_add_le_passive_scan(&req);
3938
3939 hci_req_run(&req, NULL);
3940 }
3941
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003942 hci_dev_unlock(hdev);
3943
3944 return err;
3945}
3946
Johan Hedberg33e38b32013-03-15 17:07:05 -05003947static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3948{
3949 struct pending_cmd *cmd;
3950
3951 BT_DBG("status 0x%02x", status);
3952
3953 hci_dev_lock(hdev);
3954
3955 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3956 if (!cmd)
3957 goto unlock;
3958
3959 if (status) {
3960 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3961 mgmt_status(status));
3962 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003963 struct mgmt_mode *cp = cmd->param;
3964
3965 if (cp->val)
3966 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3967 else
3968 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3969
Johan Hedberg33e38b32013-03-15 17:07:05 -05003970 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3971 new_settings(hdev, cmd->sk);
3972 }
3973
3974 mgmt_pending_remove(cmd);
3975
3976unlock:
3977 hci_dev_unlock(hdev);
3978}
3979
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003980static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003981 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003982{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003983 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003984 struct pending_cmd *cmd;
3985 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003986 int err;
3987
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003988 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003989
Johan Hedberg56f87902013-10-02 13:43:13 +03003990 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3991 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003992 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3993 MGMT_STATUS_NOT_SUPPORTED);
3994
Johan Hedberga7e80f22013-01-09 16:05:19 +02003995 if (cp->val != 0x00 && cp->val != 0x01)
3996 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3997 MGMT_STATUS_INVALID_PARAMS);
3998
Johan Hedberg5400c042012-02-21 16:40:33 +02003999 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004000 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004001 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02004002
4003 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004004 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004005 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004006
4007 hci_dev_lock(hdev);
4008
Johan Hedberg05cbf292013-03-15 17:07:07 -05004009 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
4010 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
4011 MGMT_STATUS_BUSY);
4012 goto unlock;
4013 }
4014
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05004015 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
4016 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4017 hdev);
4018 goto unlock;
4019 }
4020
Johan Hedberg33e38b32013-03-15 17:07:05 -05004021 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4022 data, len);
4023 if (!cmd) {
4024 err = -ENOMEM;
4025 goto unlock;
4026 }
4027
4028 hci_req_init(&req, hdev);
4029
Johan Hedberg406d7802013-03-15 17:07:09 -05004030 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004031
4032 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004033 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004034 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004035 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004036 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004037 }
4038
Johan Hedberg33e38b32013-03-15 17:07:05 -05004039unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004040 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004041
Antti Julkuf6422ec2011-06-22 13:11:56 +03004042 return err;
4043}
4044
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03004045static void set_bredr_scan(struct hci_request *req)
4046{
4047 struct hci_dev *hdev = req->hdev;
4048 u8 scan = 0;
4049
4050 /* Ensure that fast connectable is disabled. This function will
4051 * not do anything if the page scan parameters are already what
4052 * they should be.
4053 */
4054 write_fast_connectable(req, false);
4055
4056 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4057 scan |= SCAN_PAGE;
4058 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4059 scan |= SCAN_INQUIRY;
4060
4061 if (scan)
4062 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
4063}
4064
Johan Hedberg0663ca22013-10-02 13:43:14 +03004065static void set_bredr_complete(struct hci_dev *hdev, u8 status)
4066{
4067 struct pending_cmd *cmd;
4068
4069 BT_DBG("status 0x%02x", status);
4070
4071 hci_dev_lock(hdev);
4072
4073 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
4074 if (!cmd)
4075 goto unlock;
4076
4077 if (status) {
4078 u8 mgmt_err = mgmt_status(status);
4079
4080 /* We need to restore the flag if related HCI commands
4081 * failed.
4082 */
4083 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4084
4085 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
4086 } else {
4087 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4088 new_settings(hdev, cmd->sk);
4089 }
4090
4091 mgmt_pending_remove(cmd);
4092
4093unlock:
4094 hci_dev_unlock(hdev);
4095}
4096
4097static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4098{
4099 struct mgmt_mode *cp = data;
4100 struct pending_cmd *cmd;
4101 struct hci_request req;
4102 int err;
4103
4104 BT_DBG("request for %s", hdev->name);
4105
4106 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
4107 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4108 MGMT_STATUS_NOT_SUPPORTED);
4109
4110 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
4111 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4112 MGMT_STATUS_REJECTED);
4113
4114 if (cp->val != 0x00 && cp->val != 0x01)
4115 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4116 MGMT_STATUS_INVALID_PARAMS);
4117
4118 hci_dev_lock(hdev);
4119
4120 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4121 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4122 goto unlock;
4123 }
4124
4125 if (!hdev_is_powered(hdev)) {
4126 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004127 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4128 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4129 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4130 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
4131 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
4132 }
4133
4134 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4135
4136 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4137 if (err < 0)
4138 goto unlock;
4139
4140 err = new_settings(hdev, sk);
4141 goto unlock;
4142 }
4143
4144 /* Reject disabling when powered on */
4145 if (!cp->val) {
4146 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4147 MGMT_STATUS_REJECTED);
4148 goto unlock;
4149 }
4150
4151 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
4152 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4153 MGMT_STATUS_BUSY);
4154 goto unlock;
4155 }
4156
4157 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4158 if (!cmd) {
4159 err = -ENOMEM;
4160 goto unlock;
4161 }
4162
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004163 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03004164 * generates the correct flags.
4165 */
4166 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4167
4168 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004169
4170 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4171 set_bredr_scan(&req);
4172
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004173 /* Since only the advertising data flags will change, there
4174 * is no need to update the scan response data.
4175 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004176 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004177
Johan Hedberg0663ca22013-10-02 13:43:14 +03004178 err = hci_req_run(&req, set_bredr_complete);
4179 if (err < 0)
4180 mgmt_pending_remove(cmd);
4181
4182unlock:
4183 hci_dev_unlock(hdev);
4184 return err;
4185}
4186
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004187static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4188 void *data, u16 len)
4189{
4190 struct mgmt_mode *cp = data;
4191 struct pending_cmd *cmd;
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004192 u8 val, status;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004193 int err;
4194
4195 BT_DBG("request for %s", hdev->name);
4196
4197 status = mgmt_bredr_support(hdev);
4198 if (status)
4199 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4200 status);
4201
Marcel Holtmann5afeac142014-01-10 02:07:27 -08004202 if (!lmp_sc_capable(hdev) &&
4203 !test_bit(HCI_FORCE_SC, &hdev->dev_flags))
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004204 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4205 MGMT_STATUS_NOT_SUPPORTED);
4206
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004207 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004208 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4209 MGMT_STATUS_INVALID_PARAMS);
4210
4211 hci_dev_lock(hdev);
4212
4213 if (!hdev_is_powered(hdev)) {
4214 bool changed;
4215
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004216 if (cp->val) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004217 changed = !test_and_set_bit(HCI_SC_ENABLED,
4218 &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004219 if (cp->val == 0x02)
4220 set_bit(HCI_SC_ONLY, &hdev->dev_flags);
4221 else
4222 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4223 } else {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004224 changed = test_and_clear_bit(HCI_SC_ENABLED,
4225 &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004226 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4227 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004228
4229 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4230 if (err < 0)
4231 goto failed;
4232
4233 if (changed)
4234 err = new_settings(hdev, sk);
4235
4236 goto failed;
4237 }
4238
4239 if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
4240 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4241 MGMT_STATUS_BUSY);
4242 goto failed;
4243 }
4244
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004245 val = !!cp->val;
4246
4247 if (val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
4248 (cp->val == 0x02) == test_bit(HCI_SC_ONLY, &hdev->dev_flags)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004249 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4250 goto failed;
4251 }
4252
4253 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4254 if (!cmd) {
4255 err = -ENOMEM;
4256 goto failed;
4257 }
4258
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004259 err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004260 if (err < 0) {
4261 mgmt_pending_remove(cmd);
4262 goto failed;
4263 }
4264
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004265 if (cp->val == 0x02)
4266 set_bit(HCI_SC_ONLY, &hdev->dev_flags);
4267 else
4268 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4269
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004270failed:
4271 hci_dev_unlock(hdev);
4272 return err;
4273}
4274
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004275static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4276 void *data, u16 len)
4277{
4278 struct mgmt_mode *cp = data;
4279 bool changed;
4280 int err;
4281
4282 BT_DBG("request for %s", hdev->name);
4283
4284 if (cp->val != 0x00 && cp->val != 0x01)
4285 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4286 MGMT_STATUS_INVALID_PARAMS);
4287
4288 hci_dev_lock(hdev);
4289
4290 if (cp->val)
4291 changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
4292 else
4293 changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
4294
4295 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4296 if (err < 0)
4297 goto unlock;
4298
4299 if (changed)
4300 err = new_settings(hdev, sk);
4301
4302unlock:
4303 hci_dev_unlock(hdev);
4304 return err;
4305}
4306
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004307static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4308 u16 len)
4309{
4310 struct mgmt_cp_set_privacy *cp = cp_data;
4311 bool changed;
4312 int err;
4313
4314 BT_DBG("request for %s", hdev->name);
4315
4316 if (!lmp_le_capable(hdev))
4317 return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4318 MGMT_STATUS_NOT_SUPPORTED);
4319
4320 if (cp->privacy != 0x00 && cp->privacy != 0x01)
4321 return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4322 MGMT_STATUS_INVALID_PARAMS);
4323
4324 if (hdev_is_powered(hdev))
4325 return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4326 MGMT_STATUS_REJECTED);
4327
4328 hci_dev_lock(hdev);
4329
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004330 /* If user space supports this command it is also expected to
4331 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4332 */
4333 set_bit(HCI_RPA_RESOLVING, &hdev->dev_flags);
4334
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004335 if (cp->privacy) {
4336 changed = !test_and_set_bit(HCI_PRIVACY, &hdev->dev_flags);
4337 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
4338 set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
4339 } else {
4340 changed = test_and_clear_bit(HCI_PRIVACY, &hdev->dev_flags);
4341 memset(hdev->irk, 0, sizeof(hdev->irk));
4342 clear_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
4343 }
4344
4345 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4346 if (err < 0)
4347 goto unlock;
4348
4349 if (changed)
4350 err = new_settings(hdev, sk);
4351
4352unlock:
4353 hci_dev_unlock(hdev);
4354 return err;
4355}
4356
Johan Hedberg41edf162014-02-18 10:19:35 +02004357static bool irk_is_valid(struct mgmt_irk_info *irk)
4358{
4359 switch (irk->addr.type) {
4360 case BDADDR_LE_PUBLIC:
4361 return true;
4362
4363 case BDADDR_LE_RANDOM:
4364 /* Two most significant bits shall be set */
4365 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4366 return false;
4367 return true;
4368 }
4369
4370 return false;
4371}
4372
4373static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4374 u16 len)
4375{
4376 struct mgmt_cp_load_irks *cp = cp_data;
4377 u16 irk_count, expected_len;
4378 int i, err;
4379
4380 BT_DBG("request for %s", hdev->name);
4381
4382 if (!lmp_le_capable(hdev))
4383 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4384 MGMT_STATUS_NOT_SUPPORTED);
4385
4386 irk_count = __le16_to_cpu(cp->irk_count);
4387
4388 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4389 if (expected_len != len) {
4390 BT_ERR("load_irks: expected %u bytes, got %u bytes",
4391 len, expected_len);
4392 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4393 MGMT_STATUS_INVALID_PARAMS);
4394 }
4395
4396 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4397
4398 for (i = 0; i < irk_count; i++) {
4399 struct mgmt_irk_info *key = &cp->irks[i];
4400
4401 if (!irk_is_valid(key))
4402 return cmd_status(sk, hdev->id,
4403 MGMT_OP_LOAD_IRKS,
4404 MGMT_STATUS_INVALID_PARAMS);
4405 }
4406
4407 hci_dev_lock(hdev);
4408
4409 hci_smp_irks_clear(hdev);
4410
4411 for (i = 0; i < irk_count; i++) {
4412 struct mgmt_irk_info *irk = &cp->irks[i];
4413 u8 addr_type;
4414
4415 if (irk->addr.type == BDADDR_LE_PUBLIC)
4416 addr_type = ADDR_LE_DEV_PUBLIC;
4417 else
4418 addr_type = ADDR_LE_DEV_RANDOM;
4419
4420 hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
4421 BDADDR_ANY);
4422 }
4423
4424 set_bit(HCI_RPA_RESOLVING, &hdev->dev_flags);
4425
4426 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
4427
4428 hci_dev_unlock(hdev);
4429
4430 return err;
4431}
4432
Johan Hedberg3f706b72013-01-20 14:27:16 +02004433static bool ltk_is_valid(struct mgmt_ltk_info *key)
4434{
4435 if (key->master != 0x00 && key->master != 0x01)
4436 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004437
4438 switch (key->addr.type) {
4439 case BDADDR_LE_PUBLIC:
4440 return true;
4441
4442 case BDADDR_LE_RANDOM:
4443 /* Two most significant bits shall be set */
4444 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4445 return false;
4446 return true;
4447 }
4448
4449 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004450}
4451
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004452static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004453 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004454{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004455 struct mgmt_cp_load_long_term_keys *cp = cp_data;
4456 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004457 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004458
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004459 BT_DBG("request for %s", hdev->name);
4460
4461 if (!lmp_le_capable(hdev))
4462 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4463 MGMT_STATUS_NOT_SUPPORTED);
4464
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004465 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004466
4467 expected_len = sizeof(*cp) + key_count *
4468 sizeof(struct mgmt_ltk_info);
4469 if (expected_len != len) {
4470 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004471 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004472 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02004473 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004474 }
4475
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004476 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004477
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004478 for (i = 0; i < key_count; i++) {
4479 struct mgmt_ltk_info *key = &cp->keys[i];
4480
Johan Hedberg3f706b72013-01-20 14:27:16 +02004481 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004482 return cmd_status(sk, hdev->id,
4483 MGMT_OP_LOAD_LONG_TERM_KEYS,
4484 MGMT_STATUS_INVALID_PARAMS);
4485 }
4486
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004487 hci_dev_lock(hdev);
4488
4489 hci_smp_ltks_clear(hdev);
4490
4491 for (i = 0; i < key_count; i++) {
4492 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004493 u8 type, addr_type;
4494
4495 if (key->addr.type == BDADDR_LE_PUBLIC)
4496 addr_type = ADDR_LE_DEV_PUBLIC;
4497 else
4498 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004499
4500 if (key->master)
4501 type = HCI_SMP_LTK;
4502 else
4503 type = HCI_SMP_LTK_SLAVE;
4504
Johan Hedberg35d70272014-02-19 14:57:47 +02004505 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type,
4506 key->type, key->val, key->enc_size, key->ediv,
4507 key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004508 }
4509
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004510 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4511 NULL, 0);
4512
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004513 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004514
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004515 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004516}
4517
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004518static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004519 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4520 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004521 bool var_len;
4522 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004523} mgmt_handlers[] = {
4524 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004525 { read_version, false, MGMT_READ_VERSION_SIZE },
4526 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4527 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4528 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4529 { set_powered, false, MGMT_SETTING_SIZE },
4530 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4531 { set_connectable, false, MGMT_SETTING_SIZE },
4532 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4533 { set_pairable, false, MGMT_SETTING_SIZE },
4534 { set_link_security, false, MGMT_SETTING_SIZE },
4535 { set_ssp, false, MGMT_SETTING_SIZE },
4536 { set_hs, false, MGMT_SETTING_SIZE },
4537 { set_le, false, MGMT_SETTING_SIZE },
4538 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4539 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4540 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4541 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4542 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4543 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4544 { disconnect, false, MGMT_DISCONNECT_SIZE },
4545 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4546 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4547 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4548 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4549 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4550 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4551 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4552 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4553 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4554 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4555 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4556 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
Marcel Holtmannec109112014-01-10 02:07:30 -08004557 { add_remote_oob_data, true, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
Johan Hedbergbe22b542012-03-01 22:24:41 +02004558 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4559 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4560 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4561 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4562 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4563 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004564 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004565 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004566 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004567 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004568 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004569 { set_secure_conn, false, MGMT_SETTING_SIZE },
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004570 { set_debug_keys, false, MGMT_SETTING_SIZE },
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004571 { set_privacy, false, MGMT_SET_PRIVACY_SIZE },
Johan Hedberg41edf162014-02-18 10:19:35 +02004572 { load_irks, true, MGMT_LOAD_IRKS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004573};
4574
4575
Johan Hedberg03811012010-12-08 00:21:06 +02004576int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4577{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004578 void *buf;
4579 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004580 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004581 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004582 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004583 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004584 int err;
4585
4586 BT_DBG("got %zu bytes", msglen);
4587
4588 if (msglen < sizeof(*hdr))
4589 return -EINVAL;
4590
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004591 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004592 if (!buf)
4593 return -ENOMEM;
4594
4595 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4596 err = -EFAULT;
4597 goto done;
4598 }
4599
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004600 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004601 opcode = __le16_to_cpu(hdr->opcode);
4602 index = __le16_to_cpu(hdr->index);
4603 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004604
4605 if (len != msglen - sizeof(*hdr)) {
4606 err = -EINVAL;
4607 goto done;
4608 }
4609
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004610 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004611 hdev = hci_dev_get(index);
4612 if (!hdev) {
4613 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004614 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004615 goto done;
4616 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004617
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004618 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4619 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004620 err = cmd_status(sk, index, opcode,
4621 MGMT_STATUS_INVALID_INDEX);
4622 goto done;
4623 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004624 }
4625
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004626 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004627 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004628 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004629 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004630 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004631 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004632 }
4633
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004634 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004635 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004636 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004637 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004638 goto done;
4639 }
4640
Johan Hedbergbe22b542012-03-01 22:24:41 +02004641 handler = &mgmt_handlers[opcode];
4642
4643 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004644 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004645 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004646 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004647 goto done;
4648 }
4649
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004650 if (hdev)
4651 mgmt_init_hdev(sk, hdev);
4652
4653 cp = buf + sizeof(*hdr);
4654
Johan Hedbergbe22b542012-03-01 22:24:41 +02004655 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004656 if (err < 0)
4657 goto done;
4658
Johan Hedberg03811012010-12-08 00:21:06 +02004659 err = msglen;
4660
4661done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004662 if (hdev)
4663 hci_dev_put(hdev);
4664
Johan Hedberg03811012010-12-08 00:21:06 +02004665 kfree(buf);
4666 return err;
4667}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004668
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004669void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004670{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004671 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004672 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004673
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004674 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004675}
4676
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004677void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004678{
Johan Hedberg5f159032012-03-02 03:13:19 +02004679 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004680
Marcel Holtmann1514b892013-10-06 08:25:01 -07004681 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004682 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004683
Johan Hedberg744cf192011-11-08 20:40:14 +02004684 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004685
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004686 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004687}
4688
Andre Guedes6046dc32014-02-26 20:21:51 -03004689/* This function requires the caller holds hdev->lock */
4690static void restart_le_auto_conns(struct hci_dev *hdev)
4691{
4692 struct hci_conn_params *p;
4693
4694 list_for_each_entry(p, &hdev->le_conn_params, list) {
4695 if (p->auto_connect == HCI_AUTO_CONN_ALWAYS)
4696 hci_pend_le_conn_add(hdev, &p->addr, p->addr_type);
4697 }
4698}
4699
Johan Hedberg229ab392013-03-15 17:06:53 -05004700static void powered_complete(struct hci_dev *hdev, u8 status)
4701{
4702 struct cmd_lookup match = { NULL, hdev };
4703
4704 BT_DBG("status 0x%02x", status);
4705
4706 hci_dev_lock(hdev);
4707
Andre Guedes6046dc32014-02-26 20:21:51 -03004708 restart_le_auto_conns(hdev);
4709
Johan Hedberg229ab392013-03-15 17:06:53 -05004710 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4711
4712 new_settings(hdev, match.sk);
4713
4714 hci_dev_unlock(hdev);
4715
4716 if (match.sk)
4717 sock_put(match.sk);
4718}
4719
Johan Hedberg70da6242013-03-15 17:06:51 -05004720static int powered_update_hci(struct hci_dev *hdev)
4721{
Johan Hedberg890ea892013-03-15 17:06:52 -05004722 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004723 u8 link_sec;
4724
Johan Hedberg890ea892013-03-15 17:06:52 -05004725 hci_req_init(&req, hdev);
4726
Johan Hedberg70da6242013-03-15 17:06:51 -05004727 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4728 !lmp_host_ssp_capable(hdev)) {
4729 u8 ssp = 1;
4730
Johan Hedberg890ea892013-03-15 17:06:52 -05004731 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004732 }
4733
Johan Hedbergc73eee92013-04-19 18:35:21 +03004734 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4735 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004736 struct hci_cp_write_le_host_supported cp;
4737
4738 cp.le = 1;
4739 cp.simul = lmp_le_br_capable(hdev);
4740
4741 /* Check first if we already have the right
4742 * host state (host features set)
4743 */
4744 if (cp.le != lmp_host_le_capable(hdev) ||
4745 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004746 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4747 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004748 }
4749
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004750 if (lmp_le_capable(hdev)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004751 /* Make sure the controller has a good default for
4752 * advertising data. This also applies to the case
4753 * where BR/EDR was toggled during the AUTO_OFF phase.
4754 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004755 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004756 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004757 update_scan_rsp_data(&req);
4758 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004759
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004760 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4761 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004762 }
4763
Johan Hedberg70da6242013-03-15 17:06:51 -05004764 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4765 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004766 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4767 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004768
4769 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004770 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4771 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004772 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004773 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004774 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004775 }
4776
Johan Hedberg229ab392013-03-15 17:06:53 -05004777 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004778}
4779
Johan Hedberg744cf192011-11-08 20:40:14 +02004780int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004781{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004782 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004783 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4784 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004785 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004786
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004787 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4788 return 0;
4789
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004790 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004791 if (powered_update_hci(hdev) == 0)
4792 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004793
Johan Hedberg229ab392013-03-15 17:06:53 -05004794 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4795 &match);
4796 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004797 }
4798
Johan Hedberg229ab392013-03-15 17:06:53 -05004799 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4800 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4801
4802 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4803 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4804 zero_cod, sizeof(zero_cod), NULL);
4805
4806new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004807 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004808
4809 if (match.sk)
4810 sock_put(match.sk);
4811
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004812 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004813}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004814
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004815void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004816{
4817 struct pending_cmd *cmd;
4818 u8 status;
4819
4820 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4821 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004822 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004823
4824 if (err == -ERFKILL)
4825 status = MGMT_STATUS_RFKILLED;
4826 else
4827 status = MGMT_STATUS_FAILED;
4828
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004829 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004830
4831 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004832}
4833
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004834void mgmt_discoverable_timeout(struct hci_dev *hdev)
4835{
4836 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004837
4838 hci_dev_lock(hdev);
4839
4840 /* When discoverable timeout triggers, then just make sure
4841 * the limited discoverable flag is cleared. Even in the case
4842 * of a timeout triggered from general discoverable, it is
4843 * safe to unconditionally clear the flag.
4844 */
4845 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004846 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004847
4848 hci_req_init(&req, hdev);
Johan Hedberg4b580612013-10-19 23:38:21 +03004849 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4850 u8 scan = SCAN_PAGE;
4851 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
4852 sizeof(scan), &scan);
4853 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004854 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004855 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004856 hci_req_run(&req, NULL);
4857
4858 hdev->discov_timeout = 0;
4859
Johan Hedberg9a43e252013-10-20 19:00:07 +03004860 new_settings(hdev, NULL);
4861
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004862 hci_dev_unlock(hdev);
4863}
4864
Marcel Holtmann86a75642013-10-15 06:33:54 -07004865void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004866{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004867 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004868
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004869 /* Nothing needed here if there's a pending command since that
4870 * commands request completion callback takes care of everything
4871 * necessary.
4872 */
4873 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004874 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004875
Johan Hedbergbd107992014-02-24 14:52:19 +02004876 /* Powering off may clear the scan mode - don't let that interfere */
4877 if (!discoverable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4878 return;
4879
Johan Hedberg9a43e252013-10-20 19:00:07 +03004880 if (discoverable) {
Marcel Holtmann86a75642013-10-15 06:33:54 -07004881 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004882 } else {
4883 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmann86a75642013-10-15 06:33:54 -07004884 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004885 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004886
Johan Hedberg9a43e252013-10-20 19:00:07 +03004887 if (changed) {
4888 struct hci_request req;
4889
4890 /* In case this change in discoverable was triggered by
4891 * a disabling of connectable there could be a need to
4892 * update the advertising flags.
4893 */
4894 hci_req_init(&req, hdev);
4895 update_adv_data(&req);
4896 hci_req_run(&req, NULL);
4897
Marcel Holtmann86a75642013-10-15 06:33:54 -07004898 new_settings(hdev, NULL);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004899 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004900}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004901
Marcel Holtmanna3309162013-10-15 06:33:55 -07004902void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004903{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004904 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004905
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004906 /* Nothing needed here if there's a pending command since that
4907 * commands request completion callback takes care of everything
4908 * necessary.
4909 */
4910 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004911 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004912
Johan Hedbergce3f24c2014-02-24 14:52:20 +02004913 /* Powering off may clear the scan mode - don't let that interfere */
4914 if (!connectable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4915 return;
4916
Marcel Holtmanna3309162013-10-15 06:33:55 -07004917 if (connectable)
4918 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4919 else
4920 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004921
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004922 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004923 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004924}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02004925
Johan Hedberg778b2352014-02-24 14:52:17 +02004926void mgmt_advertising(struct hci_dev *hdev, u8 advertising)
4927{
Johan Hedberg7c4cfab2014-02-24 14:52:21 +02004928 /* Powering off may stop advertising - don't let that interfere */
4929 if (!advertising && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4930 return;
4931
Johan Hedberg778b2352014-02-24 14:52:17 +02004932 if (advertising)
4933 set_bit(HCI_ADVERTISING, &hdev->dev_flags);
4934 else
4935 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
4936}
4937
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004938void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004939{
Johan Hedbergca69b792011-11-11 18:10:00 +02004940 u8 mgmt_err = mgmt_status(status);
4941
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004942 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004943 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004944 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004945
4946 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004947 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004948 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004949}
4950
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004951void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4952 bool persistent)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02004953{
Johan Hedberg86742e12011-11-07 23:13:38 +02004954 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02004955
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004956 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02004957
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004958 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004959 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004960 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004961 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004962 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004963 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02004964
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004965 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02004966}
Johan Hedbergf7520542011-01-20 12:34:39 +02004967
Johan Hedbergba74b662014-02-19 14:57:45 +02004968void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004969{
4970 struct mgmt_ev_new_long_term_key ev;
4971
4972 memset(&ev, 0, sizeof(ev));
4973
Marcel Holtmann5192d302014-02-19 17:11:58 -08004974 /* Devices using resolvable or non-resolvable random addresses
4975 * without providing an indentity resolving key don't require
4976 * to store long term keys. Their addresses will change the
4977 * next time around.
4978 *
4979 * Only when a remote device provides an identity address
4980 * make sure the long term key is stored. If the remote
4981 * identity is known, the long term keys are internally
4982 * mapped to the identity address. So allow static random
4983 * and public addresses here.
4984 */
Johan Hedbergba74b662014-02-19 14:57:45 +02004985 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
4986 (key->bdaddr.b[5] & 0xc0) != 0xc0)
4987 ev.store_hint = 0x00;
4988 else
4989 ev.store_hint = 0x01;
4990
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004991 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004992 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Marcel Holtmannd40f3ee2014-01-31 18:42:17 -08004993 ev.key.type = key->authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004994 ev.key.enc_size = key->enc_size;
4995 ev.key.ediv = key->ediv;
4996
4997 if (key->type == HCI_SMP_LTK)
4998 ev.key.master = 1;
4999
5000 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
5001 memcpy(ev.key.val, key->val, sizeof(key->val));
5002
Marcel Holtmann083368f2013-10-15 14:26:29 -07005003 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03005004}
5005
Johan Hedberg95fbac82014-02-19 15:18:31 +02005006void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk)
5007{
5008 struct mgmt_ev_new_irk ev;
5009
5010 memset(&ev, 0, sizeof(ev));
5011
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08005012 /* For identity resolving keys from devices that are already
5013 * using a public address or static random address, do not
5014 * ask for storing this key. The identity resolving key really
5015 * is only mandatory for devices using resovlable random
5016 * addresses.
5017 *
5018 * Storing all identity resolving keys has the downside that
5019 * they will be also loaded on next boot of they system. More
5020 * identity resolving keys, means more time during scanning is
5021 * needed to actually resolve these addresses.
5022 */
5023 if (bacmp(&irk->rpa, BDADDR_ANY))
5024 ev.store_hint = 0x01;
5025 else
5026 ev.store_hint = 0x00;
5027
Johan Hedberg95fbac82014-02-19 15:18:31 +02005028 bacpy(&ev.rpa, &irk->rpa);
5029 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
5030 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
5031 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
5032
5033 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
5034}
5035
Marcel Holtmann94933992013-10-15 10:26:39 -07005036static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
5037 u8 data_len)
5038{
5039 eir[eir_len++] = sizeof(type) + data_len;
5040 eir[eir_len++] = type;
5041 memcpy(&eir[eir_len], data, data_len);
5042 eir_len += data_len;
5043
5044 return eir_len;
5045}
5046
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07005047void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5048 u8 addr_type, u32 flags, u8 *name, u8 name_len,
5049 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02005050{
Johan Hedbergb644ba32012-01-17 21:48:47 +02005051 char buf[512];
5052 struct mgmt_ev_device_connected *ev = (void *) buf;
5053 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02005054
Johan Hedbergb644ba32012-01-17 21:48:47 +02005055 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005056 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02005057
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02005058 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02005059
Johan Hedbergb644ba32012-01-17 21:48:47 +02005060 if (name_len > 0)
5061 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005062 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005063
5064 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08005065 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005066 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005067
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005068 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005069
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07005070 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
5071 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02005072}
5073
Johan Hedberg8962ee72011-01-20 12:40:27 +02005074static void disconnect_rsp(struct pending_cmd *cmd, void *data)
5075{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01005076 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005077 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02005078 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005079
Johan Hedberg88c3df12012-02-09 14:27:38 +02005080 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5081 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005082
Johan Hedbergaee9b2182012-02-18 15:07:59 +02005083 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005084 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02005085
5086 *sk = cmd->sk;
5087 sock_hold(*sk);
5088
Johan Hedberga664b5b2011-02-19 12:06:02 -03005089 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005090}
5091
Johan Hedberg124f6e32012-02-09 13:50:12 +02005092static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02005093{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02005094 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02005095 struct mgmt_cp_unpair_device *cp = cmd->param;
5096 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02005097
5098 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02005099 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5100 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02005101
Johan Hedbergb1078ad2012-02-09 17:21:16 +02005102 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
5103
Johan Hedbergaee9b2182012-02-18 15:07:59 +02005104 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02005105
5106 mgmt_pending_remove(cmd);
5107}
5108
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07005109void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02005110 u8 link_type, u8 addr_type, u8 reason,
5111 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02005112{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02005113 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8b064a32014-02-24 14:52:22 +02005114 struct pending_cmd *power_off;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005115 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005116
Johan Hedberg8b064a32014-02-24 14:52:22 +02005117 power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
5118 if (power_off) {
5119 struct mgmt_mode *cp = power_off->param;
5120
5121 /* The connection is still in hci_conn_hash so test for 1
5122 * instead of 0 to know if this is the last one.
5123 */
5124 if (!cp->val && hci_conn_count(hdev) == 1)
5125 queue_work(hdev->req_workqueue, &hdev->power_off.work);
5126 }
5127
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02005128 if (!mgmt_connected)
5129 return;
5130
Andre Guedes57eb7762013-10-30 19:01:41 -03005131 if (link_type != ACL_LINK && link_type != LE_LINK)
5132 return;
5133
Johan Hedberg744cf192011-11-08 20:40:14 +02005134 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02005135
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02005136 bacpy(&ev.addr.bdaddr, bdaddr);
5137 ev.addr.type = link_to_bdaddr(link_type, addr_type);
5138 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02005139
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07005140 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005141
5142 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01005143 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005144
Johan Hedberg124f6e32012-02-09 13:50:12 +02005145 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005146 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005147}
5148
Marcel Holtmann78929242013-10-06 23:55:47 -07005149void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
5150 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02005151{
Andre Guedes3655bba2013-10-30 19:01:40 -03005152 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
5153 struct mgmt_cp_disconnect *cp;
Johan Hedberg88c3df12012-02-09 14:27:38 +02005154 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005155 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005156
Jefferson Delfes36a75f12012-09-18 13:36:54 -04005157 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
5158 hdev);
5159
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005160 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005161 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07005162 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005163
Andre Guedes3655bba2013-10-30 19:01:40 -03005164 cp = cmd->param;
5165
5166 if (bacmp(bdaddr, &cp->addr.bdaddr))
5167 return;
5168
5169 if (cp->addr.type != bdaddr_type)
5170 return;
5171
Johan Hedberg88c3df12012-02-09 14:27:38 +02005172 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes3655bba2013-10-30 19:01:40 -03005173 rp.addr.type = bdaddr_type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02005174
Marcel Holtmann78929242013-10-06 23:55:47 -07005175 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
5176 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02005177
Johan Hedberga664b5b2011-02-19 12:06:02 -03005178 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02005179}
Johan Hedberg17d5c042011-01-22 06:09:08 +02005180
Marcel Holtmann445608d2013-10-06 23:55:48 -07005181void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5182 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02005183{
5184 struct mgmt_ev_connect_failed ev;
5185
Johan Hedberg4c659c32011-11-07 23:13:39 +02005186 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005187 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02005188 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02005189
Marcel Holtmann445608d2013-10-06 23:55:48 -07005190 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02005191}
Johan Hedberg980e1a52011-01-22 06:10:07 +02005192
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07005193void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02005194{
5195 struct mgmt_ev_pin_code_request ev;
5196
Johan Hedbergd8457692012-02-17 14:24:57 +02005197 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03005198 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02005199 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005200
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07005201 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005202}
5203
Marcel Holtmanne669cf82013-10-15 14:26:21 -07005204void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
5205 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02005206{
5207 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005208 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005209
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005210 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005211 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07005212 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005213
Johan Hedbergd8457692012-02-17 14:24:57 +02005214 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03005215 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005216
Marcel Holtmanne669cf82013-10-15 14:26:21 -07005217 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
5218 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02005219
Johan Hedberga664b5b2011-02-19 12:06:02 -03005220 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005221}
5222
Marcel Holtmann3eb38522013-10-15 14:26:22 -07005223void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
5224 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02005225{
5226 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005227 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005228
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005229 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005230 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07005231 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005232
Johan Hedbergd8457692012-02-17 14:24:57 +02005233 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03005234 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005235
Marcel Holtmann3eb38522013-10-15 14:26:22 -07005236 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
5237 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02005238
Johan Hedberga664b5b2011-02-19 12:06:02 -03005239 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005240}
Johan Hedberga5c29682011-02-19 12:05:57 -03005241
Johan Hedberg744cf192011-11-08 20:40:14 +02005242int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005243 u8 link_type, u8 addr_type, __le32 value,
5244 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03005245{
5246 struct mgmt_ev_user_confirm_request ev;
5247
Johan Hedberg744cf192011-11-08 20:40:14 +02005248 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03005249
Johan Hedberg272d90d2012-02-09 15:26:12 +02005250 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005251 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07005252 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02005253 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03005254
Johan Hedberg744cf192011-11-08 20:40:14 +02005255 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005256 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03005257}
5258
Johan Hedberg272d90d2012-02-09 15:26:12 +02005259int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03005260 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08005261{
5262 struct mgmt_ev_user_passkey_request ev;
5263
5264 BT_DBG("%s", hdev->name);
5265
Johan Hedberg272d90d2012-02-09 15:26:12 +02005266 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005267 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08005268
5269 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005270 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08005271}
5272
Brian Gix0df4c182011-11-16 13:53:13 -08005273static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03005274 u8 link_type, u8 addr_type, u8 status,
5275 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03005276{
5277 struct pending_cmd *cmd;
5278 struct mgmt_rp_user_confirm_reply rp;
5279 int err;
5280
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005281 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03005282 if (!cmd)
5283 return -ENOENT;
5284
Johan Hedberg272d90d2012-02-09 15:26:12 +02005285 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005286 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02005287 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005288 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03005289
Johan Hedberga664b5b2011-02-19 12:06:02 -03005290 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03005291
5292 return err;
5293}
5294
Johan Hedberg744cf192011-11-08 20:40:14 +02005295int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005296 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03005297{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005298 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005299 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03005300}
5301
Johan Hedberg272d90d2012-02-09 15:26:12 +02005302int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005303 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03005304{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005305 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03005306 status,
5307 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03005308}
Johan Hedberg2a611692011-02-19 12:06:00 -03005309
Brian Gix604086b2011-11-23 08:28:33 -08005310int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005311 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08005312{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005313 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005314 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08005315}
5316
Johan Hedberg272d90d2012-02-09 15:26:12 +02005317int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005318 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08005319{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005320 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03005321 status,
5322 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08005323}
5324
Johan Hedberg92a25252012-09-06 18:39:26 +03005325int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
5326 u8 link_type, u8 addr_type, u32 passkey,
5327 u8 entered)
5328{
5329 struct mgmt_ev_passkey_notify ev;
5330
5331 BT_DBG("%s", hdev->name);
5332
5333 bacpy(&ev.addr.bdaddr, bdaddr);
5334 ev.addr.type = link_to_bdaddr(link_type, addr_type);
5335 ev.passkey = __cpu_to_le32(passkey);
5336 ev.entered = entered;
5337
5338 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
5339}
5340
Marcel Holtmanne5460992013-10-15 14:26:23 -07005341void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5342 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03005343{
5344 struct mgmt_ev_auth_failed ev;
5345
Johan Hedbergbab73cb2012-02-09 16:07:29 +02005346 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005347 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02005348 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03005349
Marcel Holtmanne5460992013-10-15 14:26:23 -07005350 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03005351}
Johan Hedbergb312b1612011-03-16 14:29:37 +02005352
Marcel Holtmann464996a2013-10-15 14:26:24 -07005353void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005354{
5355 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07005356 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005357
5358 if (status) {
5359 u8 mgmt_err = mgmt_status(status);
5360 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005361 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07005362 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005363 }
5364
Marcel Holtmann464996a2013-10-15 14:26:24 -07005365 if (test_bit(HCI_AUTH, &hdev->flags))
5366 changed = !test_and_set_bit(HCI_LINK_SECURITY,
5367 &hdev->dev_flags);
5368 else
5369 changed = test_and_clear_bit(HCI_LINK_SECURITY,
5370 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02005371
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005372 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005373 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005374
Johan Hedberg47990ea2012-02-22 11:58:37 +02005375 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07005376 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005377
5378 if (match.sk)
5379 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005380}
5381
Johan Hedberg890ea892013-03-15 17:06:52 -05005382static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02005383{
Johan Hedberg890ea892013-03-15 17:06:52 -05005384 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02005385 struct hci_cp_write_eir cp;
5386
Johan Hedberg976eb202012-10-24 21:12:01 +03005387 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05005388 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02005389
Johan Hedbergc80da272012-02-22 15:38:48 +02005390 memset(hdev->eir, 0, sizeof(hdev->eir));
5391
Johan Hedbergcacaf522012-02-21 00:52:42 +02005392 memset(&cp, 0, sizeof(cp));
5393
Johan Hedberg890ea892013-03-15 17:06:52 -05005394 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02005395}
5396
Marcel Holtmann3e248562013-10-15 14:26:25 -07005397void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005398{
5399 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05005400 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005401 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005402
5403 if (status) {
5404 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005405
5406 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005407 &hdev->dev_flags)) {
5408 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07005409 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005410 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005411
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005412 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
5413 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07005414 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005415 }
5416
5417 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005418 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005419 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005420 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
5421 if (!changed)
5422 changed = test_and_clear_bit(HCI_HS_ENABLED,
5423 &hdev->dev_flags);
5424 else
5425 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005426 }
5427
5428 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
5429
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005430 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07005431 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005432
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005433 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005434 sock_put(match.sk);
5435
Johan Hedberg890ea892013-03-15 17:06:52 -05005436 hci_req_init(&req, hdev);
5437
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005438 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05005439 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005440 else
Johan Hedberg890ea892013-03-15 17:06:52 -05005441 clear_eir(&req);
5442
5443 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005444}
5445
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005446void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
5447{
5448 struct cmd_lookup match = { NULL, hdev };
5449 bool changed = false;
5450
5451 if (status) {
5452 u8 mgmt_err = mgmt_status(status);
5453
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005454 if (enable) {
5455 if (test_and_clear_bit(HCI_SC_ENABLED,
5456 &hdev->dev_flags))
5457 new_settings(hdev, NULL);
5458 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
5459 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005460
5461 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5462 cmd_status_rsp, &mgmt_err);
5463 return;
5464 }
5465
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005466 if (enable) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005467 changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005468 } else {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005469 changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005470 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
5471 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005472
5473 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5474 settings_rsp, &match);
5475
5476 if (changed)
5477 new_settings(hdev, match.sk);
5478
5479 if (match.sk)
5480 sock_put(match.sk);
5481}
5482
Johan Hedberg92da6092013-03-15 17:06:55 -05005483static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02005484{
5485 struct cmd_lookup *match = data;
5486
Johan Hedberg90e70452012-02-23 23:09:40 +02005487 if (match->sk == NULL) {
5488 match->sk = cmd->sk;
5489 sock_hold(match->sk);
5490 }
Johan Hedberg90e70452012-02-23 23:09:40 +02005491}
5492
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005493void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
5494 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005495{
Johan Hedberg90e70452012-02-23 23:09:40 +02005496 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005497
Johan Hedberg92da6092013-03-15 17:06:55 -05005498 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
5499 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
5500 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02005501
5502 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005503 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
5504 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02005505
5506 if (match.sk)
5507 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005508}
5509
Marcel Holtmann7667da32013-10-15 14:26:27 -07005510void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02005511{
Johan Hedbergb312b1612011-03-16 14:29:37 +02005512 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05005513 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005514
Johan Hedberg13928972013-03-15 17:07:00 -05005515 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07005516 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005517
5518 memset(&ev, 0, sizeof(ev));
5519 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005520 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005521
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005522 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05005523 if (!cmd) {
5524 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02005525
Johan Hedberg13928972013-03-15 17:07:00 -05005526 /* If this is a HCI command related to powering on the
5527 * HCI dev don't send any mgmt signals.
5528 */
5529 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07005530 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005531 }
5532
Marcel Holtmann7667da32013-10-15 14:26:27 -07005533 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
5534 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005535}
Szymon Jancc35938b2011-03-22 13:12:21 +01005536
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005537void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
5538 u8 *randomizer192, u8 *hash256,
5539 u8 *randomizer256, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01005540{
5541 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01005542
Johan Hedberg744cf192011-11-08 20:40:14 +02005543 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01005544
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005545 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01005546 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005547 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01005548
5549 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005550 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
5551 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01005552 } else {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005553 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
5554 hash256 && randomizer256) {
5555 struct mgmt_rp_read_local_oob_ext_data rp;
Szymon Jancc35938b2011-03-22 13:12:21 +01005556
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005557 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
5558 memcpy(rp.randomizer192, randomizer192,
5559 sizeof(rp.randomizer192));
Szymon Jancc35938b2011-03-22 13:12:21 +01005560
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005561 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
5562 memcpy(rp.randomizer256, randomizer256,
5563 sizeof(rp.randomizer256));
5564
5565 cmd_complete(cmd->sk, hdev->id,
5566 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5567 &rp, sizeof(rp));
5568 } else {
5569 struct mgmt_rp_read_local_oob_data rp;
5570
5571 memcpy(rp.hash, hash192, sizeof(rp.hash));
5572 memcpy(rp.randomizer, randomizer192,
5573 sizeof(rp.randomizer));
5574
5575 cmd_complete(cmd->sk, hdev->id,
5576 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5577 &rp, sizeof(rp));
5578 }
Szymon Jancc35938b2011-03-22 13:12:21 +01005579 }
5580
5581 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01005582}
Johan Hedberge17acd42011-03-30 23:57:16 +03005583
Marcel Holtmann901801b2013-10-06 23:55:51 -07005584void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5585 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
5586 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03005587{
Johan Hedberge319d2e2012-01-15 19:51:59 +02005588 char buf[512];
5589 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg5cedbb82014-02-18 21:41:37 +02005590 struct smp_irk *irk;
Johan Hedberg1dc06092012-01-15 21:01:23 +02005591 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03005592
Andre Guedes12602d02013-04-30 15:29:40 -03005593 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005594 return;
Andre Guedes12602d02013-04-30 15:29:40 -03005595
Johan Hedberg1dc06092012-01-15 21:01:23 +02005596 /* Leave 5 bytes for a potential CoD field */
5597 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005598 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03005599
Johan Hedberg1dc06092012-01-15 21:01:23 +02005600 memset(buf, 0, sizeof(buf));
5601
Johan Hedberg5cedbb82014-02-18 21:41:37 +02005602 irk = hci_get_irk(hdev, bdaddr, addr_type);
5603 if (irk) {
5604 bacpy(&ev->addr.bdaddr, &irk->bdaddr);
5605 ev->addr.type = link_to_bdaddr(link_type, irk->addr_type);
5606 } else {
5607 bacpy(&ev->addr.bdaddr, bdaddr);
5608 ev->addr.type = link_to_bdaddr(link_type, addr_type);
5609 }
5610
Johan Hedberge319d2e2012-01-15 19:51:59 +02005611 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02005612 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305613 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02005614 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305615 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03005616
Johan Hedberg1dc06092012-01-15 21:01:23 +02005617 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02005618 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03005619
Johan Hedberg1dc06092012-01-15 21:01:23 +02005620 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
5621 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005622 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005623
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005624 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005625 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03005626
Marcel Holtmann901801b2013-10-06 23:55:51 -07005627 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03005628}
Johan Hedberga88a9652011-03-30 13:18:12 +03005629
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005630void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5631 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03005632{
Johan Hedbergb644ba32012-01-17 21:48:47 +02005633 struct mgmt_ev_device_found *ev;
5634 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
5635 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03005636
Johan Hedbergb644ba32012-01-17 21:48:47 +02005637 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03005638
Johan Hedbergb644ba32012-01-17 21:48:47 +02005639 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03005640
Johan Hedbergb644ba32012-01-17 21:48:47 +02005641 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005642 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005643 ev->rssi = rssi;
5644
5645 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005646 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005647
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005648 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005649
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005650 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03005651}
Johan Hedberg314b2382011-04-27 10:29:57 -04005652
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005653void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04005654{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005655 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02005656 struct pending_cmd *cmd;
5657
Andre Guedes343fb142011-11-22 17:14:19 -03005658 BT_DBG("%s discovering %u", hdev->name, discovering);
5659
Johan Hedberg164a6e72011-11-01 17:06:44 +02005660 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005661 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005662 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005663 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005664
5665 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02005666 u8 type = hdev->discovery.type;
5667
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005668 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
5669 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02005670 mgmt_pending_remove(cmd);
5671 }
5672
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005673 memset(&ev, 0, sizeof(ev));
5674 ev.type = hdev->discovery.type;
5675 ev.discovering = discovering;
5676
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005677 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04005678}
Antti Julku5e762442011-08-25 16:48:02 +03005679
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005680int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005681{
5682 struct pending_cmd *cmd;
5683 struct mgmt_ev_device_blocked ev;
5684
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005685 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005686
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005687 bacpy(&ev.addr.bdaddr, bdaddr);
5688 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005689
Johan Hedberg744cf192011-11-08 20:40:14 +02005690 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005691 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005692}
5693
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005694int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005695{
5696 struct pending_cmd *cmd;
5697 struct mgmt_ev_device_unblocked ev;
5698
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005699 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005700
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005701 bacpy(&ev.addr.bdaddr, bdaddr);
5702 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005703
Johan Hedberg744cf192011-11-08 20:40:14 +02005704 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005705 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005706}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005707
5708static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5709{
5710 BT_DBG("%s status %u", hdev->name, status);
5711
5712 /* Clear the advertising mgmt setting if we failed to re-enable it */
5713 if (status) {
5714 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005715 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005716 }
5717}
5718
5719void mgmt_reenable_advertising(struct hci_dev *hdev)
5720{
5721 struct hci_request req;
5722
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005723 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005724 return;
5725
5726 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5727 return;
5728
5729 hci_req_init(&req, hdev);
5730 enable_advertising(&req);
5731
5732 /* If this fails we have no option but to let user space know
5733 * that we've disabled advertising.
5734 */
5735 if (hci_req_run(&req, adv_enable_complete) < 0) {
5736 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005737 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005738 }
5739}