blob: f878267ba6ab53d090f5399d0f9b2f65573a3691 [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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-01-17 14:41:05 +02002338
2339 hci_link_keys_clear(hdev);
2340
Johan Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-01-17 14:41:05 +02002359
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002360 return 0;
Johan Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-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 Hedberg55ed8ca12011-01-17 14:41:05 +02002382 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-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
Johan Hedberge0b2b272014-02-18 17:14:31 +02002419 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
2420 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002421
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002422 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002423 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002424 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002425 goto unlock;
2426 }
2427
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002428 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002429 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002430 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002431 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002432 else
2433 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002434 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002435 } else {
2436 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002437 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002438
Johan Hedberga8a1d192011-11-10 15:54:38 +02002439 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002440 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002441 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002442 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002443 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002444 }
2445
Johan Hedberg124f6e32012-02-09 13:50:12 +02002446 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002447 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002448 if (!cmd) {
2449 err = -ENOMEM;
2450 goto unlock;
2451 }
2452
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002453 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002454 dc.reason = 0x13; /* Remote User Terminated Connection */
2455 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2456 if (err < 0)
2457 mgmt_pending_remove(cmd);
2458
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002459unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002460 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002461 return err;
2462}
2463
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002464static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002465 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002466{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002467 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002468 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002469 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002470 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002471 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002472 int err;
2473
2474 BT_DBG("");
2475
Johan Hedberg06a63b12013-01-20 14:27:21 +02002476 memset(&rp, 0, sizeof(rp));
2477 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2478 rp.addr.type = cp->addr.type;
2479
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002480 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002481 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2482 MGMT_STATUS_INVALID_PARAMS,
2483 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002484
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002485 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002486
2487 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002488 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2489 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002490 goto failed;
2491 }
2492
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002493 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002494 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2495 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002496 goto failed;
2497 }
2498
Andre Guedes591f47f2012-04-24 21:02:49 -03002499 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002500 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2501 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002502 else
2503 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002504
Vishal Agarwalf9607272012-06-13 05:32:43 +05302505 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002506 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2507 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002508 goto failed;
2509 }
2510
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002511 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002512 if (!cmd) {
2513 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002514 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002515 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002516
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002517 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002518 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002519
2520 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2521 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002522 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002523
2524failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002525 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002526 return err;
2527}
2528
Andre Guedes57c14772012-04-24 21:02:50 -03002529static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002530{
2531 switch (link_type) {
2532 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002533 switch (addr_type) {
2534 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002535 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002536
Johan Hedberg48264f02011-11-09 13:58:58 +02002537 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002538 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002539 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002540 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002541
Johan Hedberg4c659c32011-11-07 23:13:39 +02002542 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002543 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002544 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002545 }
2546}
2547
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002548static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2549 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002550{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002551 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002552 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002553 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002554 int err;
2555 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002556
2557 BT_DBG("");
2558
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002559 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002560
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002561 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002562 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002563 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002564 goto unlock;
2565 }
2566
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002567 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002568 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2569 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002570 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002571 }
2572
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002573 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002574 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002575 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002576 err = -ENOMEM;
2577 goto unlock;
2578 }
2579
Johan Hedberg2784eb42011-01-21 13:56:35 +02002580 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002581 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002582 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2583 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002584 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002585 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002586 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002587 continue;
2588 i++;
2589 }
2590
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002591 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002592
Johan Hedberg4c659c32011-11-07 23:13:39 +02002593 /* Recalculate length in case of filtered SCO connections, etc */
2594 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002595
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002596 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002597 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002598
Johan Hedberga38528f2011-01-22 06:46:43 +02002599 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002600
2601unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002602 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002603 return err;
2604}
2605
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002606static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002607 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002608{
2609 struct pending_cmd *cmd;
2610 int err;
2611
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002612 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002613 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002614 if (!cmd)
2615 return -ENOMEM;
2616
Johan Hedbergd8457692012-02-17 14:24:57 +02002617 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002618 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002619 if (err < 0)
2620 mgmt_pending_remove(cmd);
2621
2622 return err;
2623}
2624
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002625static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002626 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002627{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002628 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002629 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002630 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002631 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002632 int err;
2633
2634 BT_DBG("");
2635
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002636 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002637
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002638 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002639 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002640 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002641 goto failed;
2642 }
2643
Johan Hedbergd8457692012-02-17 14:24:57 +02002644 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002645 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002646 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002647 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002648 goto failed;
2649 }
2650
2651 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002652 struct mgmt_cp_pin_code_neg_reply ncp;
2653
2654 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002655
2656 BT_ERR("PIN code is not 16 bytes long");
2657
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002658 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002659 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002660 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002661 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002662
2663 goto failed;
2664 }
2665
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002666 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002667 if (!cmd) {
2668 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002669 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002670 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002671
Johan Hedbergd8457692012-02-17 14:24:57 +02002672 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002673 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002674 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002675
2676 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2677 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002678 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002679
2680failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002681 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002682 return err;
2683}
2684
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002685static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2686 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002687{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002688 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002689
2690 BT_DBG("");
2691
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002692 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002693
2694 hdev->io_capability = cp->io_capability;
2695
2696 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002697 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002698
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002699 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002700
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002701 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2702 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002703}
2704
Gustavo Padovan6039aa732012-05-23 04:04:18 -03002705static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002706{
2707 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002708 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002709
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002710 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002711 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2712 continue;
2713
Johan Hedberge9a416b2011-02-19 12:05:56 -03002714 if (cmd->user_data != conn)
2715 continue;
2716
2717 return cmd;
2718 }
2719
2720 return NULL;
2721}
2722
2723static void pairing_complete(struct pending_cmd *cmd, u8 status)
2724{
2725 struct mgmt_rp_pair_device rp;
2726 struct hci_conn *conn = cmd->user_data;
2727
Johan Hedbergba4e5642011-11-11 00:07:34 +02002728 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002729 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002730
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002731 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002732 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002733
2734 /* So we don't get further callbacks for this connection */
2735 conn->connect_cfm_cb = NULL;
2736 conn->security_cfm_cb = NULL;
2737 conn->disconn_cfm_cb = NULL;
2738
David Herrmann76a68ba2013-04-06 20:28:37 +02002739 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002740
Johan Hedberga664b5b2011-02-19 12:06:02 -03002741 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002742}
2743
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002744void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2745{
2746 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
2747 struct pending_cmd *cmd;
2748
2749 cmd = find_pairing(conn);
2750 if (cmd)
2751 pairing_complete(cmd, status);
2752}
2753
Johan Hedberge9a416b2011-02-19 12:05:56 -03002754static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2755{
2756 struct pending_cmd *cmd;
2757
2758 BT_DBG("status %u", status);
2759
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002760 cmd = find_pairing(conn);
2761 if (!cmd)
2762 BT_DBG("Unable to find a pending command");
2763 else
Johan Hedberge2113262012-02-18 15:20:03 +02002764 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002765}
2766
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002767static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302768{
2769 struct pending_cmd *cmd;
2770
2771 BT_DBG("status %u", status);
2772
2773 if (!status)
2774 return;
2775
2776 cmd = find_pairing(conn);
2777 if (!cmd)
2778 BT_DBG("Unable to find a pending command");
2779 else
2780 pairing_complete(cmd, mgmt_status(status));
2781}
2782
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002783static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002784 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002785{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002786 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002787 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002788 struct pending_cmd *cmd;
2789 u8 sec_level, auth_type;
2790 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002791 int err;
2792
2793 BT_DBG("");
2794
Szymon Jancf950a30e2013-01-18 12:48:07 +01002795 memset(&rp, 0, sizeof(rp));
2796 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2797 rp.addr.type = cp->addr.type;
2798
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002799 if (!bdaddr_type_is_valid(cp->addr.type))
2800 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2801 MGMT_STATUS_INVALID_PARAMS,
2802 &rp, sizeof(rp));
2803
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002804 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002805
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002806 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002807 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2808 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002809 goto unlock;
2810 }
2811
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002812 sec_level = BT_SECURITY_MEDIUM;
2813 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002814 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002815 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002816 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002817
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002818 if (cp->addr.type == BDADDR_BREDR) {
Andre Guedes04a6c582014-02-26 20:21:44 -03002819 conn = hci_connect_acl(hdev, &cp->addr.bdaddr, sec_level,
2820 auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002821 } else {
2822 u8 addr_type;
2823
2824 /* Convert from L2CAP channel address type to HCI address type
2825 */
2826 if (cp->addr.type == BDADDR_LE_PUBLIC)
2827 addr_type = ADDR_LE_DEV_PUBLIC;
2828 else
2829 addr_type = ADDR_LE_DEV_RANDOM;
2830
2831 conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type,
Andre Guedes04a6c582014-02-26 20:21:44 -03002832 sec_level, auth_type);
Andre Guedes6f77d8c2014-02-26 20:21:45 -03002833 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002834
Ville Tervo30e76272011-02-22 16:10:53 -03002835 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002836 int status;
2837
2838 if (PTR_ERR(conn) == -EBUSY)
2839 status = MGMT_STATUS_BUSY;
2840 else
2841 status = MGMT_STATUS_CONNECT_FAILED;
2842
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002843 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002844 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002845 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002846 goto unlock;
2847 }
2848
2849 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002850 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002851 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002852 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002853 goto unlock;
2854 }
2855
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002856 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002857 if (!cmd) {
2858 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002859 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002860 goto unlock;
2861 }
2862
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002863 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002864 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002865 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002866 conn->security_cfm_cb = pairing_complete_cb;
2867 conn->disconn_cfm_cb = pairing_complete_cb;
2868 } else {
2869 conn->connect_cfm_cb = le_pairing_complete_cb;
2870 conn->security_cfm_cb = le_pairing_complete_cb;
2871 conn->disconn_cfm_cb = le_pairing_complete_cb;
2872 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002873
Johan Hedberge9a416b2011-02-19 12:05:56 -03002874 conn->io_capability = cp->io_cap;
2875 cmd->user_data = conn;
2876
2877 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002878 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002879 pairing_complete(cmd, 0);
2880
2881 err = 0;
2882
2883unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002884 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002885 return err;
2886}
2887
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002888static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2889 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002890{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002891 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002892 struct pending_cmd *cmd;
2893 struct hci_conn *conn;
2894 int err;
2895
2896 BT_DBG("");
2897
Johan Hedberg28424702012-02-02 04:02:29 +02002898 hci_dev_lock(hdev);
2899
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002900 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002901 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002902 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002903 goto unlock;
2904 }
2905
Johan Hedberg28424702012-02-02 04:02:29 +02002906 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2907 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002908 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002909 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002910 goto unlock;
2911 }
2912
2913 conn = cmd->user_data;
2914
2915 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002916 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002917 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002918 goto unlock;
2919 }
2920
2921 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2922
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002923 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002924 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002925unlock:
2926 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002927 return err;
2928}
2929
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002930static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002931 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002932 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002933{
Johan Hedberga5c29682011-02-19 12:05:57 -03002934 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002935 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002936 int err;
2937
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002938 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002939
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002940 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002941 err = cmd_complete(sk, hdev->id, mgmt_op,
2942 MGMT_STATUS_NOT_POWERED, addr,
2943 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002944 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002945 }
2946
Johan Hedberg1707c602013-03-15 17:07:15 -05002947 if (addr->type == BDADDR_BREDR)
2948 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002949 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002950 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002951
Johan Hedberg272d90d2012-02-09 15:26:12 +02002952 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002953 err = cmd_complete(sk, hdev->id, mgmt_op,
2954 MGMT_STATUS_NOT_CONNECTED, addr,
2955 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002956 goto done;
2957 }
2958
Johan Hedberg1707c602013-03-15 17:07:15 -05002959 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002960 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002961 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002962
Brian Gix5fe57d92011-12-21 16:12:13 -08002963 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002964 err = cmd_complete(sk, hdev->id, mgmt_op,
2965 MGMT_STATUS_SUCCESS, addr,
2966 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002967 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002968 err = cmd_complete(sk, hdev->id, mgmt_op,
2969 MGMT_STATUS_FAILED, addr,
2970 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002971
Brian Gix47c15e22011-11-16 13:53:14 -08002972 goto done;
2973 }
2974
Johan Hedberg1707c602013-03-15 17:07:15 -05002975 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002976 if (!cmd) {
2977 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002978 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002979 }
2980
Brian Gix0df4c182011-11-16 13:53:13 -08002981 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002982 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2983 struct hci_cp_user_passkey_reply cp;
2984
Johan Hedberg1707c602013-03-15 17:07:15 -05002985 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002986 cp.passkey = passkey;
2987 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2988 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002989 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2990 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002991
Johan Hedberga664b5b2011-02-19 12:06:02 -03002992 if (err < 0)
2993 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002994
Brian Gix0df4c182011-11-16 13:53:13 -08002995done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002996 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002997 return err;
2998}
2999
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303000static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
3001 void *data, u16 len)
3002{
3003 struct mgmt_cp_pin_code_neg_reply *cp = data;
3004
3005 BT_DBG("");
3006
Johan Hedberg1707c602013-03-15 17:07:15 -05003007 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303008 MGMT_OP_PIN_CODE_NEG_REPLY,
3009 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3010}
3011
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003012static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3013 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003014{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003015 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003016
3017 BT_DBG("");
3018
3019 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003020 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003021 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003022
Johan Hedberg1707c602013-03-15 17:07:15 -05003023 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003024 MGMT_OP_USER_CONFIRM_REPLY,
3025 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003026}
3027
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003028static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003029 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003030{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003031 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003032
3033 BT_DBG("");
3034
Johan Hedberg1707c602013-03-15 17:07:15 -05003035 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003036 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3037 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003038}
3039
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003040static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3041 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003042{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003043 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003044
3045 BT_DBG("");
3046
Johan Hedberg1707c602013-03-15 17:07:15 -05003047 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003048 MGMT_OP_USER_PASSKEY_REPLY,
3049 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003050}
3051
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003052static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003053 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003054{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003055 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003056
3057 BT_DBG("");
3058
Johan Hedberg1707c602013-03-15 17:07:15 -05003059 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003060 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3061 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003062}
3063
Johan Hedberg13928972013-03-15 17:07:00 -05003064static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003065{
Johan Hedberg13928972013-03-15 17:07:00 -05003066 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003067 struct hci_cp_write_local_name cp;
3068
Johan Hedberg13928972013-03-15 17:07:00 -05003069 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003070
Johan Hedberg890ea892013-03-15 17:06:52 -05003071 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003072}
3073
Johan Hedberg13928972013-03-15 17:07:00 -05003074static void set_name_complete(struct hci_dev *hdev, u8 status)
3075{
3076 struct mgmt_cp_set_local_name *cp;
3077 struct pending_cmd *cmd;
3078
3079 BT_DBG("status 0x%02x", status);
3080
3081 hci_dev_lock(hdev);
3082
3083 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
3084 if (!cmd)
3085 goto unlock;
3086
3087 cp = cmd->param;
3088
3089 if (status)
3090 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3091 mgmt_status(status));
3092 else
3093 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3094 cp, sizeof(*cp));
3095
3096 mgmt_pending_remove(cmd);
3097
3098unlock:
3099 hci_dev_unlock(hdev);
3100}
3101
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003102static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003103 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003104{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003105 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003106 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003107 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003108 int err;
3109
3110 BT_DBG("");
3111
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003112 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003113
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003114 /* If the old values are the same as the new ones just return a
3115 * direct command complete event.
3116 */
3117 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3118 !memcmp(hdev->short_name, cp->short_name,
3119 sizeof(hdev->short_name))) {
3120 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3121 data, len);
3122 goto failed;
3123 }
3124
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003125 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003126
Johan Hedbergb5235a62012-02-21 14:32:24 +02003127 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003128 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003129
3130 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003131 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003132 if (err < 0)
3133 goto failed;
3134
3135 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003136 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003137
Johan Hedbergb5235a62012-02-21 14:32:24 +02003138 goto failed;
3139 }
3140
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003141 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003142 if (!cmd) {
3143 err = -ENOMEM;
3144 goto failed;
3145 }
3146
Johan Hedberg13928972013-03-15 17:07:00 -05003147 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3148
Johan Hedberg890ea892013-03-15 17:06:52 -05003149 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003150
3151 if (lmp_bredr_capable(hdev)) {
3152 update_name(&req);
3153 update_eir(&req);
3154 }
3155
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003156 /* The name is stored in the scan response data and so
3157 * no need to udpate the advertising data here.
3158 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003159 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003160 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003161
Johan Hedberg13928972013-03-15 17:07:00 -05003162 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003163 if (err < 0)
3164 mgmt_pending_remove(cmd);
3165
3166failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003167 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003168 return err;
3169}
3170
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003171static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003172 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003173{
Szymon Jancc35938b2011-03-22 13:12:21 +01003174 struct pending_cmd *cmd;
3175 int err;
3176
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003177 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003178
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003179 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003180
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003181 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003182 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003183 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003184 goto unlock;
3185 }
3186
Andre Guedes9a1a1992012-07-24 15:03:48 -03003187 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003188 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003189 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003190 goto unlock;
3191 }
3192
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003193 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003194 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003195 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003196 goto unlock;
3197 }
3198
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003199 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003200 if (!cmd) {
3201 err = -ENOMEM;
3202 goto unlock;
3203 }
3204
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003205 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
3206 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
3207 0, NULL);
3208 else
3209 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3210
Szymon Jancc35938b2011-03-22 13:12:21 +01003211 if (err < 0)
3212 mgmt_pending_remove(cmd);
3213
3214unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003215 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003216 return err;
3217}
3218
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003219static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003220 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003221{
Szymon Janc2763eda2011-03-22 13:12:22 +01003222 int err;
3223
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003224 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003225
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003226 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003227
Marcel Holtmannec109112014-01-10 02:07:30 -08003228 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3229 struct mgmt_cp_add_remote_oob_data *cp = data;
3230 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003231
Marcel Holtmannec109112014-01-10 02:07:30 -08003232 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
3233 cp->hash, cp->randomizer);
3234 if (err < 0)
3235 status = MGMT_STATUS_FAILED;
3236 else
3237 status = MGMT_STATUS_SUCCESS;
3238
3239 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3240 status, &cp->addr, sizeof(cp->addr));
3241 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3242 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
3243 u8 status;
3244
3245 err = hci_add_remote_oob_ext_data(hdev, &cp->addr.bdaddr,
3246 cp->hash192,
3247 cp->randomizer192,
3248 cp->hash256,
3249 cp->randomizer256);
3250 if (err < 0)
3251 status = MGMT_STATUS_FAILED;
3252 else
3253 status = MGMT_STATUS_SUCCESS;
3254
3255 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3256 status, &cp->addr, sizeof(cp->addr));
3257 } else {
3258 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
3259 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3260 MGMT_STATUS_INVALID_PARAMS);
3261 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003262
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003263 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003264 return err;
3265}
3266
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003267static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003268 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003269{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003270 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003271 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003272 int err;
3273
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003274 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003275
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003276 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003277
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003278 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003279 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003280 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003281 else
Szymon Janca6785be2012-12-13 15:11:21 +01003282 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003283
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003284 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003285 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003286
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003287 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003288 return err;
3289}
3290
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003291static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3292{
3293 struct pending_cmd *cmd;
3294 u8 type;
3295 int err;
3296
3297 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3298
3299 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3300 if (!cmd)
3301 return -ENOENT;
3302
3303 type = hdev->discovery.type;
3304
3305 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3306 &type, sizeof(type));
3307 mgmt_pending_remove(cmd);
3308
3309 return err;
3310}
3311
Andre Guedes7c307722013-04-30 15:29:28 -03003312static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3313{
3314 BT_DBG("status %d", status);
3315
3316 if (status) {
3317 hci_dev_lock(hdev);
3318 mgmt_start_discovery_failed(hdev, status);
3319 hci_dev_unlock(hdev);
3320 return;
3321 }
3322
3323 hci_dev_lock(hdev);
3324 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3325 hci_dev_unlock(hdev);
3326
3327 switch (hdev->discovery.type) {
3328 case DISCOV_TYPE_LE:
3329 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003330 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003331 break;
3332
3333 case DISCOV_TYPE_INTERLEAVED:
3334 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003335 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003336 break;
3337
3338 case DISCOV_TYPE_BREDR:
3339 break;
3340
3341 default:
3342 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3343 }
3344}
3345
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003346static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003347 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003348{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003349 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003350 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003351 struct hci_cp_le_set_scan_param param_cp;
3352 struct hci_cp_le_set_scan_enable enable_cp;
3353 struct hci_cp_inquiry inq_cp;
3354 struct hci_request req;
3355 /* General inquiry access code (GIAC) */
3356 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedbergd9483942014-02-23 19:42:24 +02003357 u8 status, own_addr_type;
Johan Hedberg14a53662011-04-27 10:29:56 -04003358 int err;
3359
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003360 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003361
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003362 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003363
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003364 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003365 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003366 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003367 goto failed;
3368 }
3369
Andre Guedes642be6c2012-03-21 00:03:37 -03003370 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3371 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3372 MGMT_STATUS_BUSY);
3373 goto failed;
3374 }
3375
Johan Hedbergff9ef572012-01-04 14:23:45 +02003376 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003377 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003378 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003379 goto failed;
3380 }
3381
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003382 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003383 if (!cmd) {
3384 err = -ENOMEM;
3385 goto failed;
3386 }
3387
Andre Guedes4aab14e2012-02-17 20:39:36 -03003388 hdev->discovery.type = cp->type;
3389
Andre Guedes7c307722013-04-30 15:29:28 -03003390 hci_req_init(&req, hdev);
3391
Andre Guedes4aab14e2012-02-17 20:39:36 -03003392 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003393 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003394 status = mgmt_bredr_support(hdev);
3395 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003396 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003397 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003398 mgmt_pending_remove(cmd);
3399 goto failed;
3400 }
3401
Andre Guedes7c307722013-04-30 15:29:28 -03003402 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3403 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3404 MGMT_STATUS_BUSY);
3405 mgmt_pending_remove(cmd);
3406 goto failed;
3407 }
3408
3409 hci_inquiry_cache_flush(hdev);
3410
3411 memset(&inq_cp, 0, sizeof(inq_cp));
3412 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003413 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003414 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003415 break;
3416
3417 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003418 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003419 status = mgmt_le_support(hdev);
3420 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003421 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003422 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003423 mgmt_pending_remove(cmd);
3424 goto failed;
3425 }
3426
Andre Guedes7c307722013-04-30 15:29:28 -03003427 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003428 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003429 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3430 MGMT_STATUS_NOT_SUPPORTED);
3431 mgmt_pending_remove(cmd);
3432 goto failed;
3433 }
3434
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003435 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003436 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3437 MGMT_STATUS_REJECTED);
3438 mgmt_pending_remove(cmd);
3439 goto failed;
3440 }
3441
Andre Guedesc54c3862014-02-26 20:21:50 -03003442 /* If controller is scanning, it means the background scanning
3443 * is running. Thus, we should temporarily stop it in order to
3444 * set the discovery scanning parameters.
3445 */
3446 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
3447 hci_req_add_le_scan_disable(&req);
Andre Guedes7c307722013-04-30 15:29:28 -03003448
3449 memset(&param_cp, 0, sizeof(param_cp));
Johan Hedbergd9483942014-02-23 19:42:24 +02003450
Marcel Holtmann94b1fc92014-02-23 20:25:54 -08003451 /* All active scans will be done with either a resolvable
3452 * private address (when privacy feature has been enabled)
3453 * or unresolvable private address.
3454 */
3455 err = hci_update_random_address(&req, true, &own_addr_type);
Johan Hedbergd9483942014-02-23 19:42:24 +02003456 if (err < 0) {
3457 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3458 MGMT_STATUS_FAILED);
3459 mgmt_pending_remove(cmd);
3460 goto failed;
3461 }
3462
Andre Guedes7c307722013-04-30 15:29:28 -03003463 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003464 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3465 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Johan Hedbergd9483942014-02-23 19:42:24 +02003466 param_cp.own_address_type = own_addr_type;
Andre Guedes7c307722013-04-30 15:29:28 -03003467 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3468 &param_cp);
3469
3470 memset(&enable_cp, 0, sizeof(enable_cp));
3471 enable_cp.enable = LE_SCAN_ENABLE;
3472 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3473 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3474 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003475 break;
3476
Andre Guedesf39799f2012-02-17 20:39:35 -03003477 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003478 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3479 MGMT_STATUS_INVALID_PARAMS);
3480 mgmt_pending_remove(cmd);
3481 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003482 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003483
Andre Guedes7c307722013-04-30 15:29:28 -03003484 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003485 if (err < 0)
3486 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003487 else
3488 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003489
3490failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003491 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003492 return err;
3493}
3494
Andre Guedes1183fdc2013-04-30 15:29:35 -03003495static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3496{
3497 struct pending_cmd *cmd;
3498 int err;
3499
3500 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3501 if (!cmd)
3502 return -ENOENT;
3503
3504 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3505 &hdev->discovery.type, sizeof(hdev->discovery.type));
3506 mgmt_pending_remove(cmd);
3507
3508 return err;
3509}
3510
Andre Guedes0e05bba2013-04-30 15:29:33 -03003511static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3512{
3513 BT_DBG("status %d", status);
3514
3515 hci_dev_lock(hdev);
3516
3517 if (status) {
3518 mgmt_stop_discovery_failed(hdev, status);
3519 goto unlock;
3520 }
3521
3522 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3523
3524unlock:
3525 hci_dev_unlock(hdev);
3526}
3527
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003528static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003529 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003530{
Johan Hedbergd9306502012-02-20 23:25:18 +02003531 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003532 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003533 struct hci_cp_remote_name_req_cancel cp;
3534 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003535 struct hci_request req;
Johan Hedberg14a53662011-04-27 10:29:56 -04003536 int err;
3537
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003538 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003539
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003540 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003541
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003542 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003543 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003544 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3545 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003546 goto unlock;
3547 }
3548
3549 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003550 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003551 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3552 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003553 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003554 }
3555
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003556 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003557 if (!cmd) {
3558 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003559 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003560 }
3561
Andre Guedes0e05bba2013-04-30 15:29:33 -03003562 hci_req_init(&req, hdev);
3563
Andre Guedese0d9727e2012-03-20 15:15:36 -03003564 switch (hdev->discovery.state) {
3565 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003566 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3567 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3568 } else {
3569 cancel_delayed_work(&hdev->le_scan_disable);
3570
Andre Guedesb1efcc22014-02-26 20:21:40 -03003571 hci_req_add_le_scan_disable(&req);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003572 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003573
Andre Guedese0d9727e2012-03-20 15:15:36 -03003574 break;
3575
3576 case DISCOVERY_RESOLVING:
3577 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003578 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003579 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003580 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003581 err = cmd_complete(sk, hdev->id,
3582 MGMT_OP_STOP_DISCOVERY, 0,
3583 &mgmt_cp->type,
3584 sizeof(mgmt_cp->type));
3585 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3586 goto unlock;
3587 }
3588
3589 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003590 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3591 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003592
3593 break;
3594
3595 default:
3596 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003597
3598 mgmt_pending_remove(cmd);
3599 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3600 MGMT_STATUS_FAILED, &mgmt_cp->type,
3601 sizeof(mgmt_cp->type));
3602 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003603 }
3604
Andre Guedes0e05bba2013-04-30 15:29:33 -03003605 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003606 if (err < 0)
3607 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003608 else
3609 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003610
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003611unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003612 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003613 return err;
3614}
3615
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003616static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003617 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003618{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003619 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003620 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003621 int err;
3622
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003623 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003624
Johan Hedberg561aafb2012-01-04 13:31:59 +02003625 hci_dev_lock(hdev);
3626
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003627 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003628 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003629 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003630 goto failed;
3631 }
3632
Johan Hedberga198e7b2012-02-17 14:27:06 +02003633 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003634 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003635 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003636 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003637 goto failed;
3638 }
3639
3640 if (cp->name_known) {
3641 e->name_state = NAME_KNOWN;
3642 list_del(&e->list);
3643 } else {
3644 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003645 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003646 }
3647
Johan Hedberge3846622013-01-09 15:29:33 +02003648 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3649 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003650
3651failed:
3652 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003653 return err;
3654}
3655
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003656static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003657 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003658{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003659 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003660 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003661 int err;
3662
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003663 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003664
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003665 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003666 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3667 MGMT_STATUS_INVALID_PARAMS,
3668 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003669
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003670 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003671
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003672 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003673 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003674 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003675 else
Szymon Janca6785be2012-12-13 15:11:21 +01003676 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003677
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003678 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003679 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003680
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003681 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003682
3683 return err;
3684}
3685
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003686static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003687 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003688{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003689 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003690 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003691 int err;
3692
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003693 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003694
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003695 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003696 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3697 MGMT_STATUS_INVALID_PARAMS,
3698 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003699
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003700 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003701
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003702 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003703 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003704 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003705 else
Szymon Janca6785be2012-12-13 15:11:21 +01003706 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003707
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003708 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003709 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003710
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003711 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003712
3713 return err;
3714}
3715
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003716static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3717 u16 len)
3718{
3719 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003720 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003721 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003722 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003723
3724 BT_DBG("%s", hdev->name);
3725
Szymon Jancc72d4b82012-03-16 16:02:57 +01003726 source = __le16_to_cpu(cp->source);
3727
3728 if (source > 0x0002)
3729 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3730 MGMT_STATUS_INVALID_PARAMS);
3731
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003732 hci_dev_lock(hdev);
3733
Szymon Jancc72d4b82012-03-16 16:02:57 +01003734 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003735 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3736 hdev->devid_product = __le16_to_cpu(cp->product);
3737 hdev->devid_version = __le16_to_cpu(cp->version);
3738
3739 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3740
Johan Hedberg890ea892013-03-15 17:06:52 -05003741 hci_req_init(&req, hdev);
3742 update_eir(&req);
3743 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003744
3745 hci_dev_unlock(hdev);
3746
3747 return err;
3748}
3749
Johan Hedberg4375f102013-09-25 13:26:10 +03003750static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3751{
3752 struct cmd_lookup match = { NULL, hdev };
3753
3754 if (status) {
3755 u8 mgmt_err = mgmt_status(status);
3756
3757 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3758 cmd_status_rsp, &mgmt_err);
3759 return;
3760 }
3761
3762 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3763 &match);
3764
3765 new_settings(hdev, match.sk);
3766
3767 if (match.sk)
3768 sock_put(match.sk);
3769}
3770
Marcel Holtmann21b51872013-10-10 09:47:53 -07003771static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3772 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003773{
3774 struct mgmt_mode *cp = data;
3775 struct pending_cmd *cmd;
3776 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003777 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003778 int err;
3779
3780 BT_DBG("request for %s", hdev->name);
3781
Johan Hedberge6fe7982013-10-02 15:45:22 +03003782 status = mgmt_le_support(hdev);
3783 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003784 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003785 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003786
3787 if (cp->val != 0x00 && cp->val != 0x01)
3788 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3789 MGMT_STATUS_INVALID_PARAMS);
3790
3791 hci_dev_lock(hdev);
3792
3793 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003794 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003795
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003796 /* The following conditions are ones which mean that we should
3797 * not do any HCI communication but directly send a mgmt
3798 * response to user space (after toggling the flag if
3799 * necessary).
3800 */
3801 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003802 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003803 bool changed = false;
3804
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003805 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3806 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003807 changed = true;
3808 }
3809
3810 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3811 if (err < 0)
3812 goto unlock;
3813
3814 if (changed)
3815 err = new_settings(hdev, sk);
3816
3817 goto unlock;
3818 }
3819
3820 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3821 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3822 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3823 MGMT_STATUS_BUSY);
3824 goto unlock;
3825 }
3826
3827 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3828 if (!cmd) {
3829 err = -ENOMEM;
3830 goto unlock;
3831 }
3832
3833 hci_req_init(&req, hdev);
3834
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003835 if (val)
3836 enable_advertising(&req);
3837 else
3838 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003839
3840 err = hci_req_run(&req, set_advertising_complete);
3841 if (err < 0)
3842 mgmt_pending_remove(cmd);
3843
3844unlock:
3845 hci_dev_unlock(hdev);
3846 return err;
3847}
3848
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003849static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3850 void *data, u16 len)
3851{
3852 struct mgmt_cp_set_static_address *cp = data;
3853 int err;
3854
3855 BT_DBG("%s", hdev->name);
3856
Marcel Holtmann62af4442013-10-02 22:10:32 -07003857 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003858 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003859 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003860
3861 if (hdev_is_powered(hdev))
3862 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3863 MGMT_STATUS_REJECTED);
3864
3865 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3866 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3867 return cmd_status(sk, hdev->id,
3868 MGMT_OP_SET_STATIC_ADDRESS,
3869 MGMT_STATUS_INVALID_PARAMS);
3870
3871 /* Two most significant bits shall be set */
3872 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3873 return cmd_status(sk, hdev->id,
3874 MGMT_OP_SET_STATIC_ADDRESS,
3875 MGMT_STATUS_INVALID_PARAMS);
3876 }
3877
3878 hci_dev_lock(hdev);
3879
3880 bacpy(&hdev->static_addr, &cp->bdaddr);
3881
3882 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3883
3884 hci_dev_unlock(hdev);
3885
3886 return err;
3887}
3888
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003889static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3890 void *data, u16 len)
3891{
3892 struct mgmt_cp_set_scan_params *cp = data;
3893 __u16 interval, window;
3894 int err;
3895
3896 BT_DBG("%s", hdev->name);
3897
3898 if (!lmp_le_capable(hdev))
3899 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3900 MGMT_STATUS_NOT_SUPPORTED);
3901
3902 interval = __le16_to_cpu(cp->interval);
3903
3904 if (interval < 0x0004 || interval > 0x4000)
3905 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3906 MGMT_STATUS_INVALID_PARAMS);
3907
3908 window = __le16_to_cpu(cp->window);
3909
3910 if (window < 0x0004 || window > 0x4000)
3911 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3912 MGMT_STATUS_INVALID_PARAMS);
3913
Marcel Holtmann899e1072013-10-14 09:55:32 -07003914 if (window > interval)
3915 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3916 MGMT_STATUS_INVALID_PARAMS);
3917
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003918 hci_dev_lock(hdev);
3919
3920 hdev->le_scan_interval = interval;
3921 hdev->le_scan_window = window;
3922
3923 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3924
3925 hci_dev_unlock(hdev);
3926
3927 return err;
3928}
3929
Johan Hedberg33e38b32013-03-15 17:07:05 -05003930static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3931{
3932 struct pending_cmd *cmd;
3933
3934 BT_DBG("status 0x%02x", status);
3935
3936 hci_dev_lock(hdev);
3937
3938 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3939 if (!cmd)
3940 goto unlock;
3941
3942 if (status) {
3943 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3944 mgmt_status(status));
3945 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003946 struct mgmt_mode *cp = cmd->param;
3947
3948 if (cp->val)
3949 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3950 else
3951 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3952
Johan Hedberg33e38b32013-03-15 17:07:05 -05003953 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3954 new_settings(hdev, cmd->sk);
3955 }
3956
3957 mgmt_pending_remove(cmd);
3958
3959unlock:
3960 hci_dev_unlock(hdev);
3961}
3962
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003963static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003964 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003965{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003966 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003967 struct pending_cmd *cmd;
3968 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003969 int err;
3970
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003971 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003972
Johan Hedberg56f87902013-10-02 13:43:13 +03003973 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3974 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003975 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3976 MGMT_STATUS_NOT_SUPPORTED);
3977
Johan Hedberga7e80f22013-01-09 16:05:19 +02003978 if (cp->val != 0x00 && cp->val != 0x01)
3979 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3980 MGMT_STATUS_INVALID_PARAMS);
3981
Johan Hedberg5400c042012-02-21 16:40:33 +02003982 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003983 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003984 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003985
3986 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003987 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003988 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003989
3990 hci_dev_lock(hdev);
3991
Johan Hedberg05cbf292013-03-15 17:07:07 -05003992 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3993 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3994 MGMT_STATUS_BUSY);
3995 goto unlock;
3996 }
3997
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003998 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3999 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
4000 hdev);
4001 goto unlock;
4002 }
4003
Johan Hedberg33e38b32013-03-15 17:07:05 -05004004 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4005 data, len);
4006 if (!cmd) {
4007 err = -ENOMEM;
4008 goto unlock;
4009 }
4010
4011 hci_req_init(&req, hdev);
4012
Johan Hedberg406d7802013-03-15 17:07:09 -05004013 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004014
4015 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004016 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004017 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004018 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004019 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004020 }
4021
Johan Hedberg33e38b32013-03-15 17:07:05 -05004022unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004023 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004024
Antti Julkuf6422ec2011-06-22 13:11:56 +03004025 return err;
4026}
4027
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03004028static void set_bredr_scan(struct hci_request *req)
4029{
4030 struct hci_dev *hdev = req->hdev;
4031 u8 scan = 0;
4032
4033 /* Ensure that fast connectable is disabled. This function will
4034 * not do anything if the page scan parameters are already what
4035 * they should be.
4036 */
4037 write_fast_connectable(req, false);
4038
4039 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4040 scan |= SCAN_PAGE;
4041 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4042 scan |= SCAN_INQUIRY;
4043
4044 if (scan)
4045 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
4046}
4047
Johan Hedberg0663ca22013-10-02 13:43:14 +03004048static void set_bredr_complete(struct hci_dev *hdev, u8 status)
4049{
4050 struct pending_cmd *cmd;
4051
4052 BT_DBG("status 0x%02x", status);
4053
4054 hci_dev_lock(hdev);
4055
4056 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
4057 if (!cmd)
4058 goto unlock;
4059
4060 if (status) {
4061 u8 mgmt_err = mgmt_status(status);
4062
4063 /* We need to restore the flag if related HCI commands
4064 * failed.
4065 */
4066 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4067
4068 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
4069 } else {
4070 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4071 new_settings(hdev, cmd->sk);
4072 }
4073
4074 mgmt_pending_remove(cmd);
4075
4076unlock:
4077 hci_dev_unlock(hdev);
4078}
4079
4080static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4081{
4082 struct mgmt_mode *cp = data;
4083 struct pending_cmd *cmd;
4084 struct hci_request req;
4085 int err;
4086
4087 BT_DBG("request for %s", hdev->name);
4088
4089 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
4090 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4091 MGMT_STATUS_NOT_SUPPORTED);
4092
4093 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
4094 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4095 MGMT_STATUS_REJECTED);
4096
4097 if (cp->val != 0x00 && cp->val != 0x01)
4098 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4099 MGMT_STATUS_INVALID_PARAMS);
4100
4101 hci_dev_lock(hdev);
4102
4103 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4104 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4105 goto unlock;
4106 }
4107
4108 if (!hdev_is_powered(hdev)) {
4109 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004110 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4111 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4112 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4113 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
4114 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
4115 }
4116
4117 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4118
4119 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4120 if (err < 0)
4121 goto unlock;
4122
4123 err = new_settings(hdev, sk);
4124 goto unlock;
4125 }
4126
4127 /* Reject disabling when powered on */
4128 if (!cp->val) {
4129 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4130 MGMT_STATUS_REJECTED);
4131 goto unlock;
4132 }
4133
4134 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
4135 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4136 MGMT_STATUS_BUSY);
4137 goto unlock;
4138 }
4139
4140 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4141 if (!cmd) {
4142 err = -ENOMEM;
4143 goto unlock;
4144 }
4145
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004146 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03004147 * generates the correct flags.
4148 */
4149 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4150
4151 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004152
4153 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4154 set_bredr_scan(&req);
4155
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004156 /* Since only the advertising data flags will change, there
4157 * is no need to update the scan response data.
4158 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004159 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004160
Johan Hedberg0663ca22013-10-02 13:43:14 +03004161 err = hci_req_run(&req, set_bredr_complete);
4162 if (err < 0)
4163 mgmt_pending_remove(cmd);
4164
4165unlock:
4166 hci_dev_unlock(hdev);
4167 return err;
4168}
4169
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004170static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4171 void *data, u16 len)
4172{
4173 struct mgmt_mode *cp = data;
4174 struct pending_cmd *cmd;
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004175 u8 val, status;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004176 int err;
4177
4178 BT_DBG("request for %s", hdev->name);
4179
4180 status = mgmt_bredr_support(hdev);
4181 if (status)
4182 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4183 status);
4184
Marcel Holtmann5afeac142014-01-10 02:07:27 -08004185 if (!lmp_sc_capable(hdev) &&
4186 !test_bit(HCI_FORCE_SC, &hdev->dev_flags))
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004187 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4188 MGMT_STATUS_NOT_SUPPORTED);
4189
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004190 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004191 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4192 MGMT_STATUS_INVALID_PARAMS);
4193
4194 hci_dev_lock(hdev);
4195
4196 if (!hdev_is_powered(hdev)) {
4197 bool changed;
4198
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004199 if (cp->val) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004200 changed = !test_and_set_bit(HCI_SC_ENABLED,
4201 &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004202 if (cp->val == 0x02)
4203 set_bit(HCI_SC_ONLY, &hdev->dev_flags);
4204 else
4205 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4206 } else {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004207 changed = test_and_clear_bit(HCI_SC_ENABLED,
4208 &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004209 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4210 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004211
4212 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4213 if (err < 0)
4214 goto failed;
4215
4216 if (changed)
4217 err = new_settings(hdev, sk);
4218
4219 goto failed;
4220 }
4221
4222 if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
4223 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4224 MGMT_STATUS_BUSY);
4225 goto failed;
4226 }
4227
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004228 val = !!cp->val;
4229
4230 if (val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
4231 (cp->val == 0x02) == test_bit(HCI_SC_ONLY, &hdev->dev_flags)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004232 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4233 goto failed;
4234 }
4235
4236 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4237 if (!cmd) {
4238 err = -ENOMEM;
4239 goto failed;
4240 }
4241
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004242 err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004243 if (err < 0) {
4244 mgmt_pending_remove(cmd);
4245 goto failed;
4246 }
4247
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004248 if (cp->val == 0x02)
4249 set_bit(HCI_SC_ONLY, &hdev->dev_flags);
4250 else
4251 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4252
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004253failed:
4254 hci_dev_unlock(hdev);
4255 return err;
4256}
4257
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004258static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4259 void *data, u16 len)
4260{
4261 struct mgmt_mode *cp = data;
4262 bool changed;
4263 int err;
4264
4265 BT_DBG("request for %s", hdev->name);
4266
4267 if (cp->val != 0x00 && cp->val != 0x01)
4268 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4269 MGMT_STATUS_INVALID_PARAMS);
4270
4271 hci_dev_lock(hdev);
4272
4273 if (cp->val)
4274 changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
4275 else
4276 changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
4277
4278 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4279 if (err < 0)
4280 goto unlock;
4281
4282 if (changed)
4283 err = new_settings(hdev, sk);
4284
4285unlock:
4286 hci_dev_unlock(hdev);
4287 return err;
4288}
4289
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004290static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4291 u16 len)
4292{
4293 struct mgmt_cp_set_privacy *cp = cp_data;
4294 bool changed;
4295 int err;
4296
4297 BT_DBG("request for %s", hdev->name);
4298
4299 if (!lmp_le_capable(hdev))
4300 return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4301 MGMT_STATUS_NOT_SUPPORTED);
4302
4303 if (cp->privacy != 0x00 && cp->privacy != 0x01)
4304 return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4305 MGMT_STATUS_INVALID_PARAMS);
4306
4307 if (hdev_is_powered(hdev))
4308 return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4309 MGMT_STATUS_REJECTED);
4310
4311 hci_dev_lock(hdev);
4312
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004313 /* If user space supports this command it is also expected to
4314 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4315 */
4316 set_bit(HCI_RPA_RESOLVING, &hdev->dev_flags);
4317
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004318 if (cp->privacy) {
4319 changed = !test_and_set_bit(HCI_PRIVACY, &hdev->dev_flags);
4320 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
4321 set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
4322 } else {
4323 changed = test_and_clear_bit(HCI_PRIVACY, &hdev->dev_flags);
4324 memset(hdev->irk, 0, sizeof(hdev->irk));
4325 clear_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
4326 }
4327
4328 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4329 if (err < 0)
4330 goto unlock;
4331
4332 if (changed)
4333 err = new_settings(hdev, sk);
4334
4335unlock:
4336 hci_dev_unlock(hdev);
4337 return err;
4338}
4339
Johan Hedberg41edf162014-02-18 10:19:35 +02004340static bool irk_is_valid(struct mgmt_irk_info *irk)
4341{
4342 switch (irk->addr.type) {
4343 case BDADDR_LE_PUBLIC:
4344 return true;
4345
4346 case BDADDR_LE_RANDOM:
4347 /* Two most significant bits shall be set */
4348 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4349 return false;
4350 return true;
4351 }
4352
4353 return false;
4354}
4355
4356static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4357 u16 len)
4358{
4359 struct mgmt_cp_load_irks *cp = cp_data;
4360 u16 irk_count, expected_len;
4361 int i, err;
4362
4363 BT_DBG("request for %s", hdev->name);
4364
4365 if (!lmp_le_capable(hdev))
4366 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4367 MGMT_STATUS_NOT_SUPPORTED);
4368
4369 irk_count = __le16_to_cpu(cp->irk_count);
4370
4371 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4372 if (expected_len != len) {
4373 BT_ERR("load_irks: expected %u bytes, got %u bytes",
4374 len, expected_len);
4375 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4376 MGMT_STATUS_INVALID_PARAMS);
4377 }
4378
4379 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4380
4381 for (i = 0; i < irk_count; i++) {
4382 struct mgmt_irk_info *key = &cp->irks[i];
4383
4384 if (!irk_is_valid(key))
4385 return cmd_status(sk, hdev->id,
4386 MGMT_OP_LOAD_IRKS,
4387 MGMT_STATUS_INVALID_PARAMS);
4388 }
4389
4390 hci_dev_lock(hdev);
4391
4392 hci_smp_irks_clear(hdev);
4393
4394 for (i = 0; i < irk_count; i++) {
4395 struct mgmt_irk_info *irk = &cp->irks[i];
4396 u8 addr_type;
4397
4398 if (irk->addr.type == BDADDR_LE_PUBLIC)
4399 addr_type = ADDR_LE_DEV_PUBLIC;
4400 else
4401 addr_type = ADDR_LE_DEV_RANDOM;
4402
4403 hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
4404 BDADDR_ANY);
4405 }
4406
4407 set_bit(HCI_RPA_RESOLVING, &hdev->dev_flags);
4408
4409 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
4410
4411 hci_dev_unlock(hdev);
4412
4413 return err;
4414}
4415
Johan Hedberg3f706b72013-01-20 14:27:16 +02004416static bool ltk_is_valid(struct mgmt_ltk_info *key)
4417{
4418 if (key->master != 0x00 && key->master != 0x01)
4419 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004420
4421 switch (key->addr.type) {
4422 case BDADDR_LE_PUBLIC:
4423 return true;
4424
4425 case BDADDR_LE_RANDOM:
4426 /* Two most significant bits shall be set */
4427 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4428 return false;
4429 return true;
4430 }
4431
4432 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004433}
4434
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004435static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004436 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004437{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004438 struct mgmt_cp_load_long_term_keys *cp = cp_data;
4439 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004440 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004441
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004442 BT_DBG("request for %s", hdev->name);
4443
4444 if (!lmp_le_capable(hdev))
4445 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4446 MGMT_STATUS_NOT_SUPPORTED);
4447
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004448 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004449
4450 expected_len = sizeof(*cp) + key_count *
4451 sizeof(struct mgmt_ltk_info);
4452 if (expected_len != len) {
4453 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004454 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004455 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02004456 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004457 }
4458
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004459 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004460
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004461 for (i = 0; i < key_count; i++) {
4462 struct mgmt_ltk_info *key = &cp->keys[i];
4463
Johan Hedberg3f706b72013-01-20 14:27:16 +02004464 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004465 return cmd_status(sk, hdev->id,
4466 MGMT_OP_LOAD_LONG_TERM_KEYS,
4467 MGMT_STATUS_INVALID_PARAMS);
4468 }
4469
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004470 hci_dev_lock(hdev);
4471
4472 hci_smp_ltks_clear(hdev);
4473
4474 for (i = 0; i < key_count; i++) {
4475 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004476 u8 type, addr_type;
4477
4478 if (key->addr.type == BDADDR_LE_PUBLIC)
4479 addr_type = ADDR_LE_DEV_PUBLIC;
4480 else
4481 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004482
4483 if (key->master)
4484 type = HCI_SMP_LTK;
4485 else
4486 type = HCI_SMP_LTK_SLAVE;
4487
Johan Hedberg35d70272014-02-19 14:57:47 +02004488 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type,
4489 key->type, key->val, key->enc_size, key->ediv,
4490 key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004491 }
4492
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004493 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4494 NULL, 0);
4495
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004496 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004497
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004498 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004499}
4500
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004501static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004502 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4503 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004504 bool var_len;
4505 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004506} mgmt_handlers[] = {
4507 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004508 { read_version, false, MGMT_READ_VERSION_SIZE },
4509 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4510 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4511 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4512 { set_powered, false, MGMT_SETTING_SIZE },
4513 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4514 { set_connectable, false, MGMT_SETTING_SIZE },
4515 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4516 { set_pairable, false, MGMT_SETTING_SIZE },
4517 { set_link_security, false, MGMT_SETTING_SIZE },
4518 { set_ssp, false, MGMT_SETTING_SIZE },
4519 { set_hs, false, MGMT_SETTING_SIZE },
4520 { set_le, false, MGMT_SETTING_SIZE },
4521 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4522 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4523 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4524 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4525 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4526 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4527 { disconnect, false, MGMT_DISCONNECT_SIZE },
4528 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4529 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4530 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4531 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4532 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4533 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4534 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4535 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4536 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4537 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4538 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4539 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
Marcel Holtmannec109112014-01-10 02:07:30 -08004540 { add_remote_oob_data, true, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
Johan Hedbergbe22b542012-03-01 22:24:41 +02004541 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4542 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4543 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4544 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4545 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4546 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004547 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004548 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004549 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004550 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004551 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004552 { set_secure_conn, false, MGMT_SETTING_SIZE },
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004553 { set_debug_keys, false, MGMT_SETTING_SIZE },
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004554 { set_privacy, false, MGMT_SET_PRIVACY_SIZE },
Johan Hedberg41edf162014-02-18 10:19:35 +02004555 { load_irks, true, MGMT_LOAD_IRKS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004556};
4557
4558
Johan Hedberg03811012010-12-08 00:21:06 +02004559int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4560{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004561 void *buf;
4562 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004563 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004564 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004565 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004566 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004567 int err;
4568
4569 BT_DBG("got %zu bytes", msglen);
4570
4571 if (msglen < sizeof(*hdr))
4572 return -EINVAL;
4573
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004574 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004575 if (!buf)
4576 return -ENOMEM;
4577
4578 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4579 err = -EFAULT;
4580 goto done;
4581 }
4582
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004583 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004584 opcode = __le16_to_cpu(hdr->opcode);
4585 index = __le16_to_cpu(hdr->index);
4586 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004587
4588 if (len != msglen - sizeof(*hdr)) {
4589 err = -EINVAL;
4590 goto done;
4591 }
4592
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004593 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004594 hdev = hci_dev_get(index);
4595 if (!hdev) {
4596 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004597 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004598 goto done;
4599 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004600
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004601 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4602 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004603 err = cmd_status(sk, index, opcode,
4604 MGMT_STATUS_INVALID_INDEX);
4605 goto done;
4606 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004607 }
4608
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004609 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004610 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004611 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004612 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004613 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004614 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004615 }
4616
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004617 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004618 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004619 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004620 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004621 goto done;
4622 }
4623
Johan Hedbergbe22b542012-03-01 22:24:41 +02004624 handler = &mgmt_handlers[opcode];
4625
4626 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004627 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004628 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004629 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004630 goto done;
4631 }
4632
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004633 if (hdev)
4634 mgmt_init_hdev(sk, hdev);
4635
4636 cp = buf + sizeof(*hdr);
4637
Johan Hedbergbe22b542012-03-01 22:24:41 +02004638 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004639 if (err < 0)
4640 goto done;
4641
Johan Hedberg03811012010-12-08 00:21:06 +02004642 err = msglen;
4643
4644done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004645 if (hdev)
4646 hci_dev_put(hdev);
4647
Johan Hedberg03811012010-12-08 00:21:06 +02004648 kfree(buf);
4649 return err;
4650}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004651
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004652void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004653{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004654 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004655 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004656
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004657 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004658}
4659
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004660void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004661{
Johan Hedberg5f159032012-03-02 03:13:19 +02004662 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004663
Marcel Holtmann1514b892013-10-06 08:25:01 -07004664 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004665 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004666
Johan Hedberg744cf192011-11-08 20:40:14 +02004667 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004668
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004669 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004670}
4671
Andre Guedes6046dc32014-02-26 20:21:51 -03004672/* This function requires the caller holds hdev->lock */
4673static void restart_le_auto_conns(struct hci_dev *hdev)
4674{
4675 struct hci_conn_params *p;
4676
4677 list_for_each_entry(p, &hdev->le_conn_params, list) {
4678 if (p->auto_connect == HCI_AUTO_CONN_ALWAYS)
4679 hci_pend_le_conn_add(hdev, &p->addr, p->addr_type);
4680 }
4681}
4682
Johan Hedberg229ab392013-03-15 17:06:53 -05004683static void powered_complete(struct hci_dev *hdev, u8 status)
4684{
4685 struct cmd_lookup match = { NULL, hdev };
4686
4687 BT_DBG("status 0x%02x", status);
4688
4689 hci_dev_lock(hdev);
4690
Andre Guedes6046dc32014-02-26 20:21:51 -03004691 restart_le_auto_conns(hdev);
4692
Johan Hedberg229ab392013-03-15 17:06:53 -05004693 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4694
4695 new_settings(hdev, match.sk);
4696
4697 hci_dev_unlock(hdev);
4698
4699 if (match.sk)
4700 sock_put(match.sk);
4701}
4702
Johan Hedberg70da6242013-03-15 17:06:51 -05004703static int powered_update_hci(struct hci_dev *hdev)
4704{
Johan Hedberg890ea892013-03-15 17:06:52 -05004705 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004706 u8 link_sec;
4707
Johan Hedberg890ea892013-03-15 17:06:52 -05004708 hci_req_init(&req, hdev);
4709
Johan Hedberg70da6242013-03-15 17:06:51 -05004710 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4711 !lmp_host_ssp_capable(hdev)) {
4712 u8 ssp = 1;
4713
Johan Hedberg890ea892013-03-15 17:06:52 -05004714 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004715 }
4716
Johan Hedbergc73eee92013-04-19 18:35:21 +03004717 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4718 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004719 struct hci_cp_write_le_host_supported cp;
4720
4721 cp.le = 1;
4722 cp.simul = lmp_le_br_capable(hdev);
4723
4724 /* Check first if we already have the right
4725 * host state (host features set)
4726 */
4727 if (cp.le != lmp_host_le_capable(hdev) ||
4728 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004729 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4730 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004731 }
4732
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004733 if (lmp_le_capable(hdev)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004734 /* Make sure the controller has a good default for
4735 * advertising data. This also applies to the case
4736 * where BR/EDR was toggled during the AUTO_OFF phase.
4737 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004738 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004739 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004740 update_scan_rsp_data(&req);
4741 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004742
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004743 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4744 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004745 }
4746
Johan Hedberg70da6242013-03-15 17:06:51 -05004747 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4748 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004749 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4750 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004751
4752 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004753 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4754 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004755 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004756 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004757 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004758 }
4759
Johan Hedberg229ab392013-03-15 17:06:53 -05004760 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004761}
4762
Johan Hedberg744cf192011-11-08 20:40:14 +02004763int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004764{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004765 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004766 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4767 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004768 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004769
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004770 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4771 return 0;
4772
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004773 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004774 if (powered_update_hci(hdev) == 0)
4775 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004776
Johan Hedberg229ab392013-03-15 17:06:53 -05004777 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4778 &match);
4779 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004780 }
4781
Johan Hedberg229ab392013-03-15 17:06:53 -05004782 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4783 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4784
4785 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4786 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4787 zero_cod, sizeof(zero_cod), NULL);
4788
4789new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004790 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004791
4792 if (match.sk)
4793 sock_put(match.sk);
4794
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004795 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004796}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004797
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004798void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004799{
4800 struct pending_cmd *cmd;
4801 u8 status;
4802
4803 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4804 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004805 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004806
4807 if (err == -ERFKILL)
4808 status = MGMT_STATUS_RFKILLED;
4809 else
4810 status = MGMT_STATUS_FAILED;
4811
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004812 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004813
4814 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004815}
4816
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004817void mgmt_discoverable_timeout(struct hci_dev *hdev)
4818{
4819 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004820
4821 hci_dev_lock(hdev);
4822
4823 /* When discoverable timeout triggers, then just make sure
4824 * the limited discoverable flag is cleared. Even in the case
4825 * of a timeout triggered from general discoverable, it is
4826 * safe to unconditionally clear the flag.
4827 */
4828 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004829 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004830
4831 hci_req_init(&req, hdev);
Johan Hedberg4b580612013-10-19 23:38:21 +03004832 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4833 u8 scan = SCAN_PAGE;
4834 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
4835 sizeof(scan), &scan);
4836 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004837 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004838 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004839 hci_req_run(&req, NULL);
4840
4841 hdev->discov_timeout = 0;
4842
Johan Hedberg9a43e252013-10-20 19:00:07 +03004843 new_settings(hdev, NULL);
4844
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004845 hci_dev_unlock(hdev);
4846}
4847
Marcel Holtmann86a75642013-10-15 06:33:54 -07004848void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004849{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004850 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004851
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004852 /* Nothing needed here if there's a pending command since that
4853 * commands request completion callback takes care of everything
4854 * necessary.
4855 */
4856 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004857 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004858
Johan Hedbergbd107992014-02-24 14:52:19 +02004859 /* Powering off may clear the scan mode - don't let that interfere */
4860 if (!discoverable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4861 return;
4862
Johan Hedberg9a43e252013-10-20 19:00:07 +03004863 if (discoverable) {
Marcel Holtmann86a75642013-10-15 06:33:54 -07004864 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004865 } else {
4866 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmann86a75642013-10-15 06:33:54 -07004867 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004868 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004869
Johan Hedberg9a43e252013-10-20 19:00:07 +03004870 if (changed) {
4871 struct hci_request req;
4872
4873 /* In case this change in discoverable was triggered by
4874 * a disabling of connectable there could be a need to
4875 * update the advertising flags.
4876 */
4877 hci_req_init(&req, hdev);
4878 update_adv_data(&req);
4879 hci_req_run(&req, NULL);
4880
Marcel Holtmann86a75642013-10-15 06:33:54 -07004881 new_settings(hdev, NULL);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004882 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004883}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004884
Marcel Holtmanna3309162013-10-15 06:33:55 -07004885void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004886{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004887 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004888
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004889 /* Nothing needed here if there's a pending command since that
4890 * commands request completion callback takes care of everything
4891 * necessary.
4892 */
4893 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004894 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004895
Johan Hedbergce3f24c2014-02-24 14:52:20 +02004896 /* Powering off may clear the scan mode - don't let that interfere */
4897 if (!connectable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4898 return;
4899
Marcel Holtmanna3309162013-10-15 06:33:55 -07004900 if (connectable)
4901 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4902 else
4903 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004904
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004905 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004906 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004907}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004908
Johan Hedberg778b2352014-02-24 14:52:17 +02004909void mgmt_advertising(struct hci_dev *hdev, u8 advertising)
4910{
Johan Hedberg7c4cfab2014-02-24 14:52:21 +02004911 /* Powering off may stop advertising - don't let that interfere */
4912 if (!advertising && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4913 return;
4914
Johan Hedberg778b2352014-02-24 14:52:17 +02004915 if (advertising)
4916 set_bit(HCI_ADVERTISING, &hdev->dev_flags);
4917 else
4918 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
4919}
4920
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004921void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004922{
Johan Hedbergca69b792011-11-11 18:10:00 +02004923 u8 mgmt_err = mgmt_status(status);
4924
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004925 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004926 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004927 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004928
4929 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004930 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004931 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004932}
4933
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004934void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4935 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004936{
Johan Hedberg86742e12011-11-07 23:13:38 +02004937 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004938
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004939 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004940
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004941 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004942 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004943 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004944 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004945 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004946 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004947
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004948 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004949}
Johan Hedbergf7520542011-01-20 12:34:39 +02004950
Johan Hedbergba74b662014-02-19 14:57:45 +02004951void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004952{
4953 struct mgmt_ev_new_long_term_key ev;
4954
4955 memset(&ev, 0, sizeof(ev));
4956
Marcel Holtmann5192d302014-02-19 17:11:58 -08004957 /* Devices using resolvable or non-resolvable random addresses
4958 * without providing an indentity resolving key don't require
4959 * to store long term keys. Their addresses will change the
4960 * next time around.
4961 *
4962 * Only when a remote device provides an identity address
4963 * make sure the long term key is stored. If the remote
4964 * identity is known, the long term keys are internally
4965 * mapped to the identity address. So allow static random
4966 * and public addresses here.
4967 */
Johan Hedbergba74b662014-02-19 14:57:45 +02004968 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
4969 (key->bdaddr.b[5] & 0xc0) != 0xc0)
4970 ev.store_hint = 0x00;
4971 else
4972 ev.store_hint = 0x01;
4973
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004974 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004975 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Marcel Holtmannd40f3ee2014-01-31 18:42:17 -08004976 ev.key.type = key->authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004977 ev.key.enc_size = key->enc_size;
4978 ev.key.ediv = key->ediv;
4979
4980 if (key->type == HCI_SMP_LTK)
4981 ev.key.master = 1;
4982
4983 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4984 memcpy(ev.key.val, key->val, sizeof(key->val));
4985
Marcel Holtmann083368f2013-10-15 14:26:29 -07004986 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004987}
4988
Johan Hedberg95fbac82014-02-19 15:18:31 +02004989void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk)
4990{
4991 struct mgmt_ev_new_irk ev;
4992
4993 memset(&ev, 0, sizeof(ev));
4994
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08004995 /* For identity resolving keys from devices that are already
4996 * using a public address or static random address, do not
4997 * ask for storing this key. The identity resolving key really
4998 * is only mandatory for devices using resovlable random
4999 * addresses.
5000 *
5001 * Storing all identity resolving keys has the downside that
5002 * they will be also loaded on next boot of they system. More
5003 * identity resolving keys, means more time during scanning is
5004 * needed to actually resolve these addresses.
5005 */
5006 if (bacmp(&irk->rpa, BDADDR_ANY))
5007 ev.store_hint = 0x01;
5008 else
5009 ev.store_hint = 0x00;
5010
Johan Hedberg95fbac82014-02-19 15:18:31 +02005011 bacpy(&ev.rpa, &irk->rpa);
5012 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
5013 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
5014 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
5015
5016 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
5017}
5018
Marcel Holtmann94933992013-10-15 10:26:39 -07005019static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
5020 u8 data_len)
5021{
5022 eir[eir_len++] = sizeof(type) + data_len;
5023 eir[eir_len++] = type;
5024 memcpy(&eir[eir_len], data, data_len);
5025 eir_len += data_len;
5026
5027 return eir_len;
5028}
5029
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07005030void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5031 u8 addr_type, u32 flags, u8 *name, u8 name_len,
5032 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02005033{
Johan Hedbergb644ba32012-01-17 21:48:47 +02005034 char buf[512];
5035 struct mgmt_ev_device_connected *ev = (void *) buf;
5036 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02005037
Johan Hedbergb644ba32012-01-17 21:48:47 +02005038 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005039 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02005040
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02005041 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02005042
Johan Hedbergb644ba32012-01-17 21:48:47 +02005043 if (name_len > 0)
5044 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005045 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005046
5047 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08005048 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005049 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005050
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005051 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005052
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07005053 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
5054 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02005055}
5056
Johan Hedberg8962ee72011-01-20 12:40:27 +02005057static void disconnect_rsp(struct pending_cmd *cmd, void *data)
5058{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01005059 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005060 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02005061 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005062
Johan Hedberg88c3df12012-02-09 14:27:38 +02005063 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5064 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005065
Johan Hedbergaee9b2182012-02-18 15:07:59 +02005066 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005067 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02005068
5069 *sk = cmd->sk;
5070 sock_hold(*sk);
5071
Johan Hedberga664b5b2011-02-19 12:06:02 -03005072 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005073}
5074
Johan Hedberg124f6e32012-02-09 13:50:12 +02005075static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02005076{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02005077 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02005078 struct mgmt_cp_unpair_device *cp = cmd->param;
5079 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02005080
5081 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02005082 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5083 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02005084
Johan Hedbergb1078ad2012-02-09 17:21:16 +02005085 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
5086
Johan Hedbergaee9b2182012-02-18 15:07:59 +02005087 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02005088
5089 mgmt_pending_remove(cmd);
5090}
5091
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07005092void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02005093 u8 link_type, u8 addr_type, u8 reason,
5094 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02005095{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02005096 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8b064a32014-02-24 14:52:22 +02005097 struct pending_cmd *power_off;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005098 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005099
Johan Hedberg8b064a32014-02-24 14:52:22 +02005100 power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
5101 if (power_off) {
5102 struct mgmt_mode *cp = power_off->param;
5103
5104 /* The connection is still in hci_conn_hash so test for 1
5105 * instead of 0 to know if this is the last one.
5106 */
5107 if (!cp->val && hci_conn_count(hdev) == 1)
5108 queue_work(hdev->req_workqueue, &hdev->power_off.work);
5109 }
5110
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02005111 if (!mgmt_connected)
5112 return;
5113
Andre Guedes57eb7762013-10-30 19:01:41 -03005114 if (link_type != ACL_LINK && link_type != LE_LINK)
5115 return;
5116
Johan Hedberg744cf192011-11-08 20:40:14 +02005117 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02005118
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02005119 bacpy(&ev.addr.bdaddr, bdaddr);
5120 ev.addr.type = link_to_bdaddr(link_type, addr_type);
5121 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02005122
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07005123 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005124
5125 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01005126 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005127
Johan Hedberg124f6e32012-02-09 13:50:12 +02005128 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005129 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005130}
5131
Marcel Holtmann78929242013-10-06 23:55:47 -07005132void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
5133 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02005134{
Andre Guedes3655bba2013-10-30 19:01:40 -03005135 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
5136 struct mgmt_cp_disconnect *cp;
Johan Hedberg88c3df12012-02-09 14:27:38 +02005137 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005138 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005139
Jefferson Delfes36a75f12012-09-18 13:36:54 -04005140 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
5141 hdev);
5142
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005143 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005144 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07005145 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005146
Andre Guedes3655bba2013-10-30 19:01:40 -03005147 cp = cmd->param;
5148
5149 if (bacmp(bdaddr, &cp->addr.bdaddr))
5150 return;
5151
5152 if (cp->addr.type != bdaddr_type)
5153 return;
5154
Johan Hedberg88c3df12012-02-09 14:27:38 +02005155 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes3655bba2013-10-30 19:01:40 -03005156 rp.addr.type = bdaddr_type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02005157
Marcel Holtmann78929242013-10-06 23:55:47 -07005158 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
5159 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02005160
Johan Hedberga664b5b2011-02-19 12:06:02 -03005161 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02005162}
Johan Hedberg17d5c042011-01-22 06:09:08 +02005163
Marcel Holtmann445608d2013-10-06 23:55:48 -07005164void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5165 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02005166{
5167 struct mgmt_ev_connect_failed ev;
5168
Johan Hedberg4c659c32011-11-07 23:13:39 +02005169 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005170 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02005171 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02005172
Marcel Holtmann445608d2013-10-06 23:55:48 -07005173 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02005174}
Johan Hedberg980e1a52011-01-22 06:10:07 +02005175
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07005176void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02005177{
5178 struct mgmt_ev_pin_code_request ev;
5179
Johan Hedbergd8457692012-02-17 14:24:57 +02005180 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03005181 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02005182 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005183
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07005184 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005185}
5186
Marcel Holtmanne669cf82013-10-15 14:26:21 -07005187void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
5188 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02005189{
5190 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005191 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005192
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005193 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005194 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07005195 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005196
Johan Hedbergd8457692012-02-17 14:24:57 +02005197 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03005198 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005199
Marcel Holtmanne669cf82013-10-15 14:26:21 -07005200 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
5201 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02005202
Johan Hedberga664b5b2011-02-19 12:06:02 -03005203 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005204}
5205
Marcel Holtmann3eb38522013-10-15 14:26:22 -07005206void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
5207 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02005208{
5209 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005210 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005211
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005212 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005213 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07005214 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005215
Johan Hedbergd8457692012-02-17 14:24:57 +02005216 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03005217 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005218
Marcel Holtmann3eb38522013-10-15 14:26:22 -07005219 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
5220 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02005221
Johan Hedberga664b5b2011-02-19 12:06:02 -03005222 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005223}
Johan Hedberga5c29682011-02-19 12:05:57 -03005224
Johan Hedberg744cf192011-11-08 20:40:14 +02005225int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005226 u8 link_type, u8 addr_type, __le32 value,
5227 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03005228{
5229 struct mgmt_ev_user_confirm_request ev;
5230
Johan Hedberg744cf192011-11-08 20:40:14 +02005231 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03005232
Johan Hedberg272d90d2012-02-09 15:26:12 +02005233 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005234 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07005235 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02005236 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03005237
Johan Hedberg744cf192011-11-08 20:40:14 +02005238 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005239 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03005240}
5241
Johan Hedberg272d90d2012-02-09 15:26:12 +02005242int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03005243 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08005244{
5245 struct mgmt_ev_user_passkey_request ev;
5246
5247 BT_DBG("%s", hdev->name);
5248
Johan Hedberg272d90d2012-02-09 15:26:12 +02005249 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005250 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08005251
5252 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005253 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08005254}
5255
Brian Gix0df4c182011-11-16 13:53:13 -08005256static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03005257 u8 link_type, u8 addr_type, u8 status,
5258 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03005259{
5260 struct pending_cmd *cmd;
5261 struct mgmt_rp_user_confirm_reply rp;
5262 int err;
5263
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005264 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03005265 if (!cmd)
5266 return -ENOENT;
5267
Johan Hedberg272d90d2012-02-09 15:26:12 +02005268 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005269 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02005270 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005271 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03005272
Johan Hedberga664b5b2011-02-19 12:06:02 -03005273 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03005274
5275 return err;
5276}
5277
Johan Hedberg744cf192011-11-08 20:40:14 +02005278int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005279 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03005280{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005281 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005282 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03005283}
5284
Johan Hedberg272d90d2012-02-09 15:26:12 +02005285int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005286 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03005287{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005288 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03005289 status,
5290 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03005291}
Johan Hedberg2a611692011-02-19 12:06:00 -03005292
Brian Gix604086b2011-11-23 08:28:33 -08005293int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005294 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08005295{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005296 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005297 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08005298}
5299
Johan Hedberg272d90d2012-02-09 15:26:12 +02005300int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005301 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08005302{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005303 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03005304 status,
5305 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08005306}
5307
Johan Hedberg92a25252012-09-06 18:39:26 +03005308int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
5309 u8 link_type, u8 addr_type, u32 passkey,
5310 u8 entered)
5311{
5312 struct mgmt_ev_passkey_notify ev;
5313
5314 BT_DBG("%s", hdev->name);
5315
5316 bacpy(&ev.addr.bdaddr, bdaddr);
5317 ev.addr.type = link_to_bdaddr(link_type, addr_type);
5318 ev.passkey = __cpu_to_le32(passkey);
5319 ev.entered = entered;
5320
5321 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
5322}
5323
Marcel Holtmanne5460992013-10-15 14:26:23 -07005324void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5325 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03005326{
5327 struct mgmt_ev_auth_failed ev;
5328
Johan Hedbergbab73cb2012-02-09 16:07:29 +02005329 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005330 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02005331 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03005332
Marcel Holtmanne5460992013-10-15 14:26:23 -07005333 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03005334}
Johan Hedbergb312b1612011-03-16 14:29:37 +02005335
Marcel Holtmann464996a2013-10-15 14:26:24 -07005336void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005337{
5338 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07005339 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005340
5341 if (status) {
5342 u8 mgmt_err = mgmt_status(status);
5343 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005344 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07005345 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005346 }
5347
Marcel Holtmann464996a2013-10-15 14:26:24 -07005348 if (test_bit(HCI_AUTH, &hdev->flags))
5349 changed = !test_and_set_bit(HCI_LINK_SECURITY,
5350 &hdev->dev_flags);
5351 else
5352 changed = test_and_clear_bit(HCI_LINK_SECURITY,
5353 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02005354
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005355 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005356 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005357
Johan Hedberg47990ea2012-02-22 11:58:37 +02005358 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07005359 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005360
5361 if (match.sk)
5362 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005363}
5364
Johan Hedberg890ea892013-03-15 17:06:52 -05005365static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02005366{
Johan Hedberg890ea892013-03-15 17:06:52 -05005367 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02005368 struct hci_cp_write_eir cp;
5369
Johan Hedberg976eb202012-10-24 21:12:01 +03005370 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05005371 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02005372
Johan Hedbergc80da272012-02-22 15:38:48 +02005373 memset(hdev->eir, 0, sizeof(hdev->eir));
5374
Johan Hedbergcacaf522012-02-21 00:52:42 +02005375 memset(&cp, 0, sizeof(cp));
5376
Johan Hedberg890ea892013-03-15 17:06:52 -05005377 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02005378}
5379
Marcel Holtmann3e248562013-10-15 14:26:25 -07005380void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005381{
5382 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05005383 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005384 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005385
5386 if (status) {
5387 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005388
5389 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005390 &hdev->dev_flags)) {
5391 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07005392 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005393 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005394
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005395 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
5396 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07005397 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005398 }
5399
5400 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005401 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005402 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005403 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
5404 if (!changed)
5405 changed = test_and_clear_bit(HCI_HS_ENABLED,
5406 &hdev->dev_flags);
5407 else
5408 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005409 }
5410
5411 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
5412
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005413 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07005414 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005415
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005416 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005417 sock_put(match.sk);
5418
Johan Hedberg890ea892013-03-15 17:06:52 -05005419 hci_req_init(&req, hdev);
5420
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005421 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05005422 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005423 else
Johan Hedberg890ea892013-03-15 17:06:52 -05005424 clear_eir(&req);
5425
5426 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005427}
5428
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005429void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
5430{
5431 struct cmd_lookup match = { NULL, hdev };
5432 bool changed = false;
5433
5434 if (status) {
5435 u8 mgmt_err = mgmt_status(status);
5436
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005437 if (enable) {
5438 if (test_and_clear_bit(HCI_SC_ENABLED,
5439 &hdev->dev_flags))
5440 new_settings(hdev, NULL);
5441 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
5442 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005443
5444 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5445 cmd_status_rsp, &mgmt_err);
5446 return;
5447 }
5448
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005449 if (enable) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005450 changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005451 } else {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005452 changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005453 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
5454 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005455
5456 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5457 settings_rsp, &match);
5458
5459 if (changed)
5460 new_settings(hdev, match.sk);
5461
5462 if (match.sk)
5463 sock_put(match.sk);
5464}
5465
Johan Hedberg92da6092013-03-15 17:06:55 -05005466static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02005467{
5468 struct cmd_lookup *match = data;
5469
Johan Hedberg90e70452012-02-23 23:09:40 +02005470 if (match->sk == NULL) {
5471 match->sk = cmd->sk;
5472 sock_hold(match->sk);
5473 }
Johan Hedberg90e70452012-02-23 23:09:40 +02005474}
5475
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005476void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
5477 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005478{
Johan Hedberg90e70452012-02-23 23:09:40 +02005479 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005480
Johan Hedberg92da6092013-03-15 17:06:55 -05005481 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
5482 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
5483 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02005484
5485 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005486 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
5487 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02005488
5489 if (match.sk)
5490 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005491}
5492
Marcel Holtmann7667da32013-10-15 14:26:27 -07005493void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02005494{
Johan Hedbergb312b1612011-03-16 14:29:37 +02005495 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05005496 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005497
Johan Hedberg13928972013-03-15 17:07:00 -05005498 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07005499 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005500
5501 memset(&ev, 0, sizeof(ev));
5502 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005503 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005504
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005505 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05005506 if (!cmd) {
5507 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02005508
Johan Hedberg13928972013-03-15 17:07:00 -05005509 /* If this is a HCI command related to powering on the
5510 * HCI dev don't send any mgmt signals.
5511 */
5512 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07005513 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005514 }
5515
Marcel Holtmann7667da32013-10-15 14:26:27 -07005516 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
5517 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005518}
Szymon Jancc35938b2011-03-22 13:12:21 +01005519
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005520void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
5521 u8 *randomizer192, u8 *hash256,
5522 u8 *randomizer256, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01005523{
5524 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01005525
Johan Hedberg744cf192011-11-08 20:40:14 +02005526 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01005527
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005528 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01005529 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005530 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01005531
5532 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005533 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
5534 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01005535 } else {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005536 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
5537 hash256 && randomizer256) {
5538 struct mgmt_rp_read_local_oob_ext_data rp;
Szymon Jancc35938b2011-03-22 13:12:21 +01005539
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005540 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
5541 memcpy(rp.randomizer192, randomizer192,
5542 sizeof(rp.randomizer192));
Szymon Jancc35938b2011-03-22 13:12:21 +01005543
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005544 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
5545 memcpy(rp.randomizer256, randomizer256,
5546 sizeof(rp.randomizer256));
5547
5548 cmd_complete(cmd->sk, hdev->id,
5549 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5550 &rp, sizeof(rp));
5551 } else {
5552 struct mgmt_rp_read_local_oob_data rp;
5553
5554 memcpy(rp.hash, hash192, sizeof(rp.hash));
5555 memcpy(rp.randomizer, randomizer192,
5556 sizeof(rp.randomizer));
5557
5558 cmd_complete(cmd->sk, hdev->id,
5559 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5560 &rp, sizeof(rp));
5561 }
Szymon Jancc35938b2011-03-22 13:12:21 +01005562 }
5563
5564 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01005565}
Johan Hedberge17acd42011-03-30 23:57:16 +03005566
Marcel Holtmann901801b2013-10-06 23:55:51 -07005567void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5568 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
5569 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03005570{
Johan Hedberge319d2e2012-01-15 19:51:59 +02005571 char buf[512];
5572 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg5cedbb82014-02-18 21:41:37 +02005573 struct smp_irk *irk;
Johan Hedberg1dc06092012-01-15 21:01:23 +02005574 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03005575
Andre Guedes12602d02013-04-30 15:29:40 -03005576 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005577 return;
Andre Guedes12602d02013-04-30 15:29:40 -03005578
Johan Hedberg1dc06092012-01-15 21:01:23 +02005579 /* Leave 5 bytes for a potential CoD field */
5580 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005581 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03005582
Johan Hedberg1dc06092012-01-15 21:01:23 +02005583 memset(buf, 0, sizeof(buf));
5584
Johan Hedberg5cedbb82014-02-18 21:41:37 +02005585 irk = hci_get_irk(hdev, bdaddr, addr_type);
5586 if (irk) {
5587 bacpy(&ev->addr.bdaddr, &irk->bdaddr);
5588 ev->addr.type = link_to_bdaddr(link_type, irk->addr_type);
5589 } else {
5590 bacpy(&ev->addr.bdaddr, bdaddr);
5591 ev->addr.type = link_to_bdaddr(link_type, addr_type);
5592 }
5593
Johan Hedberge319d2e2012-01-15 19:51:59 +02005594 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02005595 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305596 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02005597 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305598 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03005599
Johan Hedberg1dc06092012-01-15 21:01:23 +02005600 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02005601 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03005602
Johan Hedberg1dc06092012-01-15 21:01:23 +02005603 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
5604 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005605 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005606
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005607 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005608 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03005609
Marcel Holtmann901801b2013-10-06 23:55:51 -07005610 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03005611}
Johan Hedberga88a9652011-03-30 13:18:12 +03005612
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005613void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5614 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03005615{
Johan Hedbergb644ba32012-01-17 21:48:47 +02005616 struct mgmt_ev_device_found *ev;
5617 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
5618 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03005619
Johan Hedbergb644ba32012-01-17 21:48:47 +02005620 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03005621
Johan Hedbergb644ba32012-01-17 21:48:47 +02005622 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03005623
Johan Hedbergb644ba32012-01-17 21:48:47 +02005624 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005625 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005626 ev->rssi = rssi;
5627
5628 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005629 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005630
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005631 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005632
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005633 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03005634}
Johan Hedberg314b2382011-04-27 10:29:57 -04005635
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005636void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04005637{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005638 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02005639 struct pending_cmd *cmd;
5640
Andre Guedes343fb142011-11-22 17:14:19 -03005641 BT_DBG("%s discovering %u", hdev->name, discovering);
5642
Johan Hedberg164a6e72011-11-01 17:06:44 +02005643 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005644 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005645 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005646 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005647
5648 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02005649 u8 type = hdev->discovery.type;
5650
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005651 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
5652 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02005653 mgmt_pending_remove(cmd);
5654 }
5655
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005656 memset(&ev, 0, sizeof(ev));
5657 ev.type = hdev->discovery.type;
5658 ev.discovering = discovering;
5659
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005660 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04005661}
Antti Julku5e762442011-08-25 16:48:02 +03005662
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005663int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005664{
5665 struct pending_cmd *cmd;
5666 struct mgmt_ev_device_blocked ev;
5667
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005668 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005669
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005670 bacpy(&ev.addr.bdaddr, bdaddr);
5671 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005672
Johan Hedberg744cf192011-11-08 20:40:14 +02005673 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005674 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005675}
5676
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005677int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005678{
5679 struct pending_cmd *cmd;
5680 struct mgmt_ev_device_unblocked ev;
5681
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005682 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005683
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005684 bacpy(&ev.addr.bdaddr, bdaddr);
5685 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005686
Johan Hedberg744cf192011-11-08 20:40:14 +02005687 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005688 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005689}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005690
5691static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5692{
5693 BT_DBG("%s status %u", hdev->name, status);
5694
5695 /* Clear the advertising mgmt setting if we failed to re-enable it */
5696 if (status) {
5697 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005698 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005699 }
5700}
5701
5702void mgmt_reenable_advertising(struct hci_dev *hdev)
5703{
5704 struct hci_request req;
5705
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005706 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005707 return;
5708
5709 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5710 return;
5711
5712 hci_req_init(&req, hdev);
5713 enable_advertising(&req);
5714
5715 /* If this fails we have no option but to let user space know
5716 * that we've disabled advertising.
5717 */
5718 if (hci_req_run(&req, adv_enable_complete) < 0) {
5719 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005720 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005721 }
5722}