blob: 9fc7c1d9fcbb896caa11b3d435f57bfa19e9e66e [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070033
34#include "smp.h"
Johan Hedberg03811012010-12-08 00:21:06 +020035
Johan Hedberg2da9c552012-02-17 14:39:28 +020036#define MGMT_VERSION 1
Marcel Holtmann40456642014-01-28 15:39:01 -080037#define MGMT_REVISION 5
Johan Hedberg02d98122010-12-13 21:07:04 +020038
Johan Hedberge70bb2e2012-02-13 16:59:33 +020039static const u16 mgmt_commands[] = {
40 MGMT_OP_READ_INDEX_LIST,
41 MGMT_OP_READ_INFO,
42 MGMT_OP_SET_POWERED,
43 MGMT_OP_SET_DISCOVERABLE,
44 MGMT_OP_SET_CONNECTABLE,
45 MGMT_OP_SET_FAST_CONNECTABLE,
46 MGMT_OP_SET_PAIRABLE,
47 MGMT_OP_SET_LINK_SECURITY,
48 MGMT_OP_SET_SSP,
49 MGMT_OP_SET_HS,
50 MGMT_OP_SET_LE,
51 MGMT_OP_SET_DEV_CLASS,
52 MGMT_OP_SET_LOCAL_NAME,
53 MGMT_OP_ADD_UUID,
54 MGMT_OP_REMOVE_UUID,
55 MGMT_OP_LOAD_LINK_KEYS,
56 MGMT_OP_LOAD_LONG_TERM_KEYS,
57 MGMT_OP_DISCONNECT,
58 MGMT_OP_GET_CONNECTIONS,
59 MGMT_OP_PIN_CODE_REPLY,
60 MGMT_OP_PIN_CODE_NEG_REPLY,
61 MGMT_OP_SET_IO_CAPABILITY,
62 MGMT_OP_PAIR_DEVICE,
63 MGMT_OP_CANCEL_PAIR_DEVICE,
64 MGMT_OP_UNPAIR_DEVICE,
65 MGMT_OP_USER_CONFIRM_REPLY,
66 MGMT_OP_USER_CONFIRM_NEG_REPLY,
67 MGMT_OP_USER_PASSKEY_REPLY,
68 MGMT_OP_USER_PASSKEY_NEG_REPLY,
69 MGMT_OP_READ_LOCAL_OOB_DATA,
70 MGMT_OP_ADD_REMOTE_OOB_DATA,
71 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
72 MGMT_OP_START_DISCOVERY,
73 MGMT_OP_STOP_DISCOVERY,
74 MGMT_OP_CONFIRM_NAME,
75 MGMT_OP_BLOCK_DEVICE,
76 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070077 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030078 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030079 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070080 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070081 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080082 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080083 MGMT_OP_SET_DEBUG_KEYS,
Johan 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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200208
Andre Guedes790eff42012-06-07 19:05:46 -0300209 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200225 kfree_skb(skb);
226
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300227 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200228}
229
Johan Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Holtmann5afeac12014-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200427
Johan Hedberg84bde9d6c2012-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 Hedbergf7b64e692010-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 Hedberg84bde9d6c2012-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 Hedbergaee9b212012-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 Hedbergf7b64e692010-12-13 21:07:06 +02001307
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001308 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +02001434 if (err < 0)
1435 mgmt_pending_remove(cmd);
1436
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001437failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001438 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-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 Hedberge8ba3a1f2013-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 Hedbergf7b64e692010-12-13 21:07:06 +02001543{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001544 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedberge8ba3a1f2013-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 Padovan6039aa72012-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 Hedbergaee9b212012-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 Guedes591f47f2012-04-24 21:02:49 -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);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002821 else
Andre Guedes04a6c582014-02-26 20:21:44 -03002822 conn = hci_connect_le(hdev, &cp->addr.bdaddr, cp->addr.type,
2823 sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002824
Ville Tervo30e76272011-02-22 16:10:53 -03002825 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002826 int status;
2827
2828 if (PTR_ERR(conn) == -EBUSY)
2829 status = MGMT_STATUS_BUSY;
2830 else
2831 status = MGMT_STATUS_CONNECT_FAILED;
2832
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002833 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002834 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002835 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002836 goto unlock;
2837 }
2838
2839 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002840 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002841 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002842 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002843 goto unlock;
2844 }
2845
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002846 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002847 if (!cmd) {
2848 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002849 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002850 goto unlock;
2851 }
2852
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002853 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002854 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002855 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002856 conn->security_cfm_cb = pairing_complete_cb;
2857 conn->disconn_cfm_cb = pairing_complete_cb;
2858 } else {
2859 conn->connect_cfm_cb = le_pairing_complete_cb;
2860 conn->security_cfm_cb = le_pairing_complete_cb;
2861 conn->disconn_cfm_cb = le_pairing_complete_cb;
2862 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002863
Johan Hedberge9a416b2011-02-19 12:05:56 -03002864 conn->io_capability = cp->io_cap;
2865 cmd->user_data = conn;
2866
2867 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002868 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002869 pairing_complete(cmd, 0);
2870
2871 err = 0;
2872
2873unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002874 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002875 return err;
2876}
2877
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002878static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2879 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002880{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002881 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002882 struct pending_cmd *cmd;
2883 struct hci_conn *conn;
2884 int err;
2885
2886 BT_DBG("");
2887
Johan Hedberg28424702012-02-02 04:02:29 +02002888 hci_dev_lock(hdev);
2889
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002890 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002891 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002892 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002893 goto unlock;
2894 }
2895
Johan Hedberg28424702012-02-02 04:02:29 +02002896 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2897 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002898 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002899 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002900 goto unlock;
2901 }
2902
2903 conn = cmd->user_data;
2904
2905 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002906 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002907 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002908 goto unlock;
2909 }
2910
2911 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2912
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002913 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002914 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002915unlock:
2916 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002917 return err;
2918}
2919
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002920static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002921 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002922 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002923{
Johan Hedberga5c29682011-02-19 12:05:57 -03002924 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002925 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002926 int err;
2927
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002928 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002929
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002930 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002931 err = cmd_complete(sk, hdev->id, mgmt_op,
2932 MGMT_STATUS_NOT_POWERED, addr,
2933 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002934 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002935 }
2936
Johan Hedberg1707c602013-03-15 17:07:15 -05002937 if (addr->type == BDADDR_BREDR)
2938 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002939 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002940 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002941
Johan Hedberg272d90d2012-02-09 15:26:12 +02002942 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002943 err = cmd_complete(sk, hdev->id, mgmt_op,
2944 MGMT_STATUS_NOT_CONNECTED, addr,
2945 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002946 goto done;
2947 }
2948
Johan Hedberg1707c602013-03-15 17:07:15 -05002949 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002950 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002951 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002952
Brian Gix5fe57d92011-12-21 16:12:13 -08002953 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002954 err = cmd_complete(sk, hdev->id, mgmt_op,
2955 MGMT_STATUS_SUCCESS, addr,
2956 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002957 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002958 err = cmd_complete(sk, hdev->id, mgmt_op,
2959 MGMT_STATUS_FAILED, addr,
2960 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002961
Brian Gix47c15e22011-11-16 13:53:14 -08002962 goto done;
2963 }
2964
Johan Hedberg1707c602013-03-15 17:07:15 -05002965 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002966 if (!cmd) {
2967 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002968 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002969 }
2970
Brian Gix0df4c182011-11-16 13:53:13 -08002971 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002972 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2973 struct hci_cp_user_passkey_reply cp;
2974
Johan Hedberg1707c602013-03-15 17:07:15 -05002975 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002976 cp.passkey = passkey;
2977 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2978 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002979 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2980 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002981
Johan Hedberga664b5b2011-02-19 12:06:02 -03002982 if (err < 0)
2983 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002984
Brian Gix0df4c182011-11-16 13:53:13 -08002985done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002986 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002987 return err;
2988}
2989
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302990static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2991 void *data, u16 len)
2992{
2993 struct mgmt_cp_pin_code_neg_reply *cp = data;
2994
2995 BT_DBG("");
2996
Johan Hedberg1707c602013-03-15 17:07:15 -05002997 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302998 MGMT_OP_PIN_CODE_NEG_REPLY,
2999 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3000}
3001
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003002static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3003 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003004{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003005 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003006
3007 BT_DBG("");
3008
3009 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003010 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003011 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003012
Johan Hedberg1707c602013-03-15 17:07:15 -05003013 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003014 MGMT_OP_USER_CONFIRM_REPLY,
3015 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003016}
3017
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003018static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003019 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003020{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003021 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003022
3023 BT_DBG("");
3024
Johan Hedberg1707c602013-03-15 17:07:15 -05003025 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003026 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3027 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003028}
3029
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003030static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3031 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003032{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003033 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003034
3035 BT_DBG("");
3036
Johan Hedberg1707c602013-03-15 17:07:15 -05003037 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003038 MGMT_OP_USER_PASSKEY_REPLY,
3039 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003040}
3041
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003042static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003043 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003044{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003045 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003046
3047 BT_DBG("");
3048
Johan Hedberg1707c602013-03-15 17:07:15 -05003049 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003050 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3051 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003052}
3053
Johan Hedberg13928972013-03-15 17:07:00 -05003054static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003055{
Johan Hedberg13928972013-03-15 17:07:00 -05003056 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003057 struct hci_cp_write_local_name cp;
3058
Johan Hedberg13928972013-03-15 17:07:00 -05003059 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003060
Johan Hedberg890ea892013-03-15 17:06:52 -05003061 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003062}
3063
Johan Hedberg13928972013-03-15 17:07:00 -05003064static void set_name_complete(struct hci_dev *hdev, u8 status)
3065{
3066 struct mgmt_cp_set_local_name *cp;
3067 struct pending_cmd *cmd;
3068
3069 BT_DBG("status 0x%02x", status);
3070
3071 hci_dev_lock(hdev);
3072
3073 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
3074 if (!cmd)
3075 goto unlock;
3076
3077 cp = cmd->param;
3078
3079 if (status)
3080 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3081 mgmt_status(status));
3082 else
3083 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3084 cp, sizeof(*cp));
3085
3086 mgmt_pending_remove(cmd);
3087
3088unlock:
3089 hci_dev_unlock(hdev);
3090}
3091
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003092static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003093 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003094{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003095 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003096 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003097 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003098 int err;
3099
3100 BT_DBG("");
3101
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003102 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003103
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003104 /* If the old values are the same as the new ones just return a
3105 * direct command complete event.
3106 */
3107 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3108 !memcmp(hdev->short_name, cp->short_name,
3109 sizeof(hdev->short_name))) {
3110 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3111 data, len);
3112 goto failed;
3113 }
3114
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003115 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003116
Johan Hedbergb5235a62012-02-21 14:32:24 +02003117 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003118 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003119
3120 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003121 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003122 if (err < 0)
3123 goto failed;
3124
3125 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003126 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003127
Johan Hedbergb5235a62012-02-21 14:32:24 +02003128 goto failed;
3129 }
3130
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003131 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003132 if (!cmd) {
3133 err = -ENOMEM;
3134 goto failed;
3135 }
3136
Johan Hedberg13928972013-03-15 17:07:00 -05003137 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3138
Johan Hedberg890ea892013-03-15 17:06:52 -05003139 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003140
3141 if (lmp_bredr_capable(hdev)) {
3142 update_name(&req);
3143 update_eir(&req);
3144 }
3145
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003146 /* The name is stored in the scan response data and so
3147 * no need to udpate the advertising data here.
3148 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003149 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003150 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003151
Johan Hedberg13928972013-03-15 17:07:00 -05003152 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003153 if (err < 0)
3154 mgmt_pending_remove(cmd);
3155
3156failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003157 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003158 return err;
3159}
3160
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003161static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003162 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003163{
Szymon Jancc35938b2011-03-22 13:12:21 +01003164 struct pending_cmd *cmd;
3165 int err;
3166
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003167 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003168
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003169 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003170
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003171 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003172 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003173 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003174 goto unlock;
3175 }
3176
Andre Guedes9a1a1992012-07-24 15:03:48 -03003177 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003178 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003179 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003180 goto unlock;
3181 }
3182
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003183 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003184 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003185 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003186 goto unlock;
3187 }
3188
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003189 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003190 if (!cmd) {
3191 err = -ENOMEM;
3192 goto unlock;
3193 }
3194
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003195 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
3196 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
3197 0, NULL);
3198 else
3199 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3200
Szymon Jancc35938b2011-03-22 13:12:21 +01003201 if (err < 0)
3202 mgmt_pending_remove(cmd);
3203
3204unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003205 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003206 return err;
3207}
3208
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003209static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003210 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003211{
Szymon Janc2763eda2011-03-22 13:12:22 +01003212 int err;
3213
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003214 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003215
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003216 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003217
Marcel Holtmannec109112014-01-10 02:07:30 -08003218 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3219 struct mgmt_cp_add_remote_oob_data *cp = data;
3220 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003221
Marcel Holtmannec109112014-01-10 02:07:30 -08003222 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
3223 cp->hash, cp->randomizer);
3224 if (err < 0)
3225 status = MGMT_STATUS_FAILED;
3226 else
3227 status = MGMT_STATUS_SUCCESS;
3228
3229 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3230 status, &cp->addr, sizeof(cp->addr));
3231 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3232 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
3233 u8 status;
3234
3235 err = hci_add_remote_oob_ext_data(hdev, &cp->addr.bdaddr,
3236 cp->hash192,
3237 cp->randomizer192,
3238 cp->hash256,
3239 cp->randomizer256);
3240 if (err < 0)
3241 status = MGMT_STATUS_FAILED;
3242 else
3243 status = MGMT_STATUS_SUCCESS;
3244
3245 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3246 status, &cp->addr, sizeof(cp->addr));
3247 } else {
3248 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
3249 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3250 MGMT_STATUS_INVALID_PARAMS);
3251 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003252
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003253 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003254 return err;
3255}
3256
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003257static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003258 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003259{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003260 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003261 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003262 int err;
3263
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003264 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003265
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003266 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003267
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003268 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003269 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003270 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003271 else
Szymon Janca6785be2012-12-13 15:11:21 +01003272 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003273
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003274 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003275 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003276
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003277 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003278 return err;
3279}
3280
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003281static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3282{
3283 struct pending_cmd *cmd;
3284 u8 type;
3285 int err;
3286
3287 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3288
3289 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3290 if (!cmd)
3291 return -ENOENT;
3292
3293 type = hdev->discovery.type;
3294
3295 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3296 &type, sizeof(type));
3297 mgmt_pending_remove(cmd);
3298
3299 return err;
3300}
3301
Andre Guedes7c307722013-04-30 15:29:28 -03003302static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3303{
3304 BT_DBG("status %d", status);
3305
3306 if (status) {
3307 hci_dev_lock(hdev);
3308 mgmt_start_discovery_failed(hdev, status);
3309 hci_dev_unlock(hdev);
3310 return;
3311 }
3312
3313 hci_dev_lock(hdev);
3314 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3315 hci_dev_unlock(hdev);
3316
3317 switch (hdev->discovery.type) {
3318 case DISCOV_TYPE_LE:
3319 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003320 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003321 break;
3322
3323 case DISCOV_TYPE_INTERLEAVED:
3324 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003325 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003326 break;
3327
3328 case DISCOV_TYPE_BREDR:
3329 break;
3330
3331 default:
3332 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3333 }
3334}
3335
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003336static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003337 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003338{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003339 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003340 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003341 struct hci_cp_le_set_scan_param param_cp;
3342 struct hci_cp_le_set_scan_enable enable_cp;
3343 struct hci_cp_inquiry inq_cp;
3344 struct hci_request req;
3345 /* General inquiry access code (GIAC) */
3346 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedbergd9483942014-02-23 19:42:24 +02003347 u8 status, own_addr_type;
Johan Hedberg14a53662011-04-27 10:29:56 -04003348 int err;
3349
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003350 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003351
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003352 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003353
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003354 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003355 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003356 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003357 goto failed;
3358 }
3359
Andre Guedes642be6c2012-03-21 00:03:37 -03003360 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3361 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3362 MGMT_STATUS_BUSY);
3363 goto failed;
3364 }
3365
Johan Hedbergff9ef572012-01-04 14:23:45 +02003366 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003367 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003368 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003369 goto failed;
3370 }
3371
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003372 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003373 if (!cmd) {
3374 err = -ENOMEM;
3375 goto failed;
3376 }
3377
Andre Guedes4aab14e2012-02-17 20:39:36 -03003378 hdev->discovery.type = cp->type;
3379
Andre Guedes7c307722013-04-30 15:29:28 -03003380 hci_req_init(&req, hdev);
3381
Andre Guedes4aab14e2012-02-17 20:39:36 -03003382 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003383 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003384 status = mgmt_bredr_support(hdev);
3385 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003386 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003387 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003388 mgmt_pending_remove(cmd);
3389 goto failed;
3390 }
3391
Andre Guedes7c307722013-04-30 15:29:28 -03003392 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3393 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3394 MGMT_STATUS_BUSY);
3395 mgmt_pending_remove(cmd);
3396 goto failed;
3397 }
3398
3399 hci_inquiry_cache_flush(hdev);
3400
3401 memset(&inq_cp, 0, sizeof(inq_cp));
3402 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003403 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003404 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003405 break;
3406
3407 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003408 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003409 status = mgmt_le_support(hdev);
3410 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003411 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003412 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003413 mgmt_pending_remove(cmd);
3414 goto failed;
3415 }
3416
Andre Guedes7c307722013-04-30 15:29:28 -03003417 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003418 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003419 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3420 MGMT_STATUS_NOT_SUPPORTED);
3421 mgmt_pending_remove(cmd);
3422 goto failed;
3423 }
3424
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003425 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003426 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3427 MGMT_STATUS_REJECTED);
3428 mgmt_pending_remove(cmd);
3429 goto failed;
3430 }
3431
3432 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3433 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3434 MGMT_STATUS_BUSY);
3435 mgmt_pending_remove(cmd);
3436 goto failed;
3437 }
3438
3439 memset(&param_cp, 0, sizeof(param_cp));
Johan Hedbergd9483942014-02-23 19:42:24 +02003440
Marcel Holtmann94b1fc92014-02-23 20:25:54 -08003441 /* All active scans will be done with either a resolvable
3442 * private address (when privacy feature has been enabled)
3443 * or unresolvable private address.
3444 */
3445 err = hci_update_random_address(&req, true, &own_addr_type);
Johan Hedbergd9483942014-02-23 19:42:24 +02003446 if (err < 0) {
3447 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3448 MGMT_STATUS_FAILED);
3449 mgmt_pending_remove(cmd);
3450 goto failed;
3451 }
3452
Andre Guedes7c307722013-04-30 15:29:28 -03003453 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003454 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3455 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Johan Hedbergd9483942014-02-23 19:42:24 +02003456 param_cp.own_address_type = own_addr_type;
Andre Guedes7c307722013-04-30 15:29:28 -03003457 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3458 &param_cp);
3459
3460 memset(&enable_cp, 0, sizeof(enable_cp));
3461 enable_cp.enable = LE_SCAN_ENABLE;
3462 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3463 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3464 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003465 break;
3466
Andre Guedesf39799f2012-02-17 20:39:35 -03003467 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003468 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3469 MGMT_STATUS_INVALID_PARAMS);
3470 mgmt_pending_remove(cmd);
3471 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003472 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003473
Andre Guedes7c307722013-04-30 15:29:28 -03003474 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003475 if (err < 0)
3476 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003477 else
3478 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003479
3480failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003481 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003482 return err;
3483}
3484
Andre Guedes1183fdc2013-04-30 15:29:35 -03003485static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3486{
3487 struct pending_cmd *cmd;
3488 int err;
3489
3490 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3491 if (!cmd)
3492 return -ENOENT;
3493
3494 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3495 &hdev->discovery.type, sizeof(hdev->discovery.type));
3496 mgmt_pending_remove(cmd);
3497
3498 return err;
3499}
3500
Andre Guedes0e05bba2013-04-30 15:29:33 -03003501static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3502{
3503 BT_DBG("status %d", status);
3504
3505 hci_dev_lock(hdev);
3506
3507 if (status) {
3508 mgmt_stop_discovery_failed(hdev, status);
3509 goto unlock;
3510 }
3511
3512 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3513
3514unlock:
3515 hci_dev_unlock(hdev);
3516}
3517
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003518static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003519 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003520{
Johan Hedbergd9306502012-02-20 23:25:18 +02003521 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003522 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003523 struct hci_cp_remote_name_req_cancel cp;
3524 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003525 struct hci_request req;
Johan Hedberg14a53662011-04-27 10:29:56 -04003526 int err;
3527
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003528 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003529
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003530 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003531
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003532 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003533 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003534 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3535 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003536 goto unlock;
3537 }
3538
3539 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003540 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003541 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3542 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003543 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003544 }
3545
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003546 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003547 if (!cmd) {
3548 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003549 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003550 }
3551
Andre Guedes0e05bba2013-04-30 15:29:33 -03003552 hci_req_init(&req, hdev);
3553
Andre Guedese0d9727e2012-03-20 15:15:36 -03003554 switch (hdev->discovery.state) {
3555 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003556 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3557 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3558 } else {
3559 cancel_delayed_work(&hdev->le_scan_disable);
3560
Andre Guedesb1efcc22014-02-26 20:21:40 -03003561 hci_req_add_le_scan_disable(&req);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003562 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003563
Andre Guedese0d9727e2012-03-20 15:15:36 -03003564 break;
3565
3566 case DISCOVERY_RESOLVING:
3567 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003568 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003569 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003570 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003571 err = cmd_complete(sk, hdev->id,
3572 MGMT_OP_STOP_DISCOVERY, 0,
3573 &mgmt_cp->type,
3574 sizeof(mgmt_cp->type));
3575 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3576 goto unlock;
3577 }
3578
3579 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003580 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3581 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003582
3583 break;
3584
3585 default:
3586 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003587
3588 mgmt_pending_remove(cmd);
3589 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3590 MGMT_STATUS_FAILED, &mgmt_cp->type,
3591 sizeof(mgmt_cp->type));
3592 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003593 }
3594
Andre Guedes0e05bba2013-04-30 15:29:33 -03003595 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003596 if (err < 0)
3597 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003598 else
3599 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003600
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003601unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003602 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003603 return err;
3604}
3605
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003606static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003607 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003608{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003609 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003610 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003611 int err;
3612
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003613 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003614
Johan Hedberg561aafb2012-01-04 13:31:59 +02003615 hci_dev_lock(hdev);
3616
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003617 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003618 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003619 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003620 goto failed;
3621 }
3622
Johan Hedberga198e7b2012-02-17 14:27:06 +02003623 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003624 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003625 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003626 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003627 goto failed;
3628 }
3629
3630 if (cp->name_known) {
3631 e->name_state = NAME_KNOWN;
3632 list_del(&e->list);
3633 } else {
3634 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003635 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003636 }
3637
Johan Hedberge3846622013-01-09 15:29:33 +02003638 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3639 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003640
3641failed:
3642 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003643 return err;
3644}
3645
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003646static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003647 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003648{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003649 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003650 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003651 int err;
3652
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003653 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003654
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003655 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003656 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3657 MGMT_STATUS_INVALID_PARAMS,
3658 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003659
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003660 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003661
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003662 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003663 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003664 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003665 else
Szymon Janca6785be2012-12-13 15:11:21 +01003666 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003667
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003668 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003669 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003670
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003671 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003672
3673 return err;
3674}
3675
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003676static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003677 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003678{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003679 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003680 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003681 int err;
3682
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003683 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003684
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003685 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003686 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3687 MGMT_STATUS_INVALID_PARAMS,
3688 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003689
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003690 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003691
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003692 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003693 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003694 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003695 else
Szymon Janca6785be2012-12-13 15:11:21 +01003696 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003697
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003698 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003699 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003700
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003701 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003702
3703 return err;
3704}
3705
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003706static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3707 u16 len)
3708{
3709 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003710 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003711 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003712 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003713
3714 BT_DBG("%s", hdev->name);
3715
Szymon Jancc72d4b82012-03-16 16:02:57 +01003716 source = __le16_to_cpu(cp->source);
3717
3718 if (source > 0x0002)
3719 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3720 MGMT_STATUS_INVALID_PARAMS);
3721
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003722 hci_dev_lock(hdev);
3723
Szymon Jancc72d4b82012-03-16 16:02:57 +01003724 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003725 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3726 hdev->devid_product = __le16_to_cpu(cp->product);
3727 hdev->devid_version = __le16_to_cpu(cp->version);
3728
3729 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3730
Johan Hedberg890ea892013-03-15 17:06:52 -05003731 hci_req_init(&req, hdev);
3732 update_eir(&req);
3733 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003734
3735 hci_dev_unlock(hdev);
3736
3737 return err;
3738}
3739
Johan Hedberg4375f102013-09-25 13:26:10 +03003740static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3741{
3742 struct cmd_lookup match = { NULL, hdev };
3743
3744 if (status) {
3745 u8 mgmt_err = mgmt_status(status);
3746
3747 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3748 cmd_status_rsp, &mgmt_err);
3749 return;
3750 }
3751
3752 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3753 &match);
3754
3755 new_settings(hdev, match.sk);
3756
3757 if (match.sk)
3758 sock_put(match.sk);
3759}
3760
Marcel Holtmann21b51872013-10-10 09:47:53 -07003761static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3762 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003763{
3764 struct mgmt_mode *cp = data;
3765 struct pending_cmd *cmd;
3766 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003767 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003768 int err;
3769
3770 BT_DBG("request for %s", hdev->name);
3771
Johan Hedberge6fe7982013-10-02 15:45:22 +03003772 status = mgmt_le_support(hdev);
3773 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003774 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003775 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003776
3777 if (cp->val != 0x00 && cp->val != 0x01)
3778 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3779 MGMT_STATUS_INVALID_PARAMS);
3780
3781 hci_dev_lock(hdev);
3782
3783 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003784 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003785
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003786 /* The following conditions are ones which mean that we should
3787 * not do any HCI communication but directly send a mgmt
3788 * response to user space (after toggling the flag if
3789 * necessary).
3790 */
3791 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003792 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003793 bool changed = false;
3794
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003795 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3796 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003797 changed = true;
3798 }
3799
3800 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3801 if (err < 0)
3802 goto unlock;
3803
3804 if (changed)
3805 err = new_settings(hdev, sk);
3806
3807 goto unlock;
3808 }
3809
3810 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3811 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3812 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3813 MGMT_STATUS_BUSY);
3814 goto unlock;
3815 }
3816
3817 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3818 if (!cmd) {
3819 err = -ENOMEM;
3820 goto unlock;
3821 }
3822
3823 hci_req_init(&req, hdev);
3824
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003825 if (val)
3826 enable_advertising(&req);
3827 else
3828 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003829
3830 err = hci_req_run(&req, set_advertising_complete);
3831 if (err < 0)
3832 mgmt_pending_remove(cmd);
3833
3834unlock:
3835 hci_dev_unlock(hdev);
3836 return err;
3837}
3838
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003839static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3840 void *data, u16 len)
3841{
3842 struct mgmt_cp_set_static_address *cp = data;
3843 int err;
3844
3845 BT_DBG("%s", hdev->name);
3846
Marcel Holtmann62af4442013-10-02 22:10:32 -07003847 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003848 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003849 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003850
3851 if (hdev_is_powered(hdev))
3852 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3853 MGMT_STATUS_REJECTED);
3854
3855 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3856 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3857 return cmd_status(sk, hdev->id,
3858 MGMT_OP_SET_STATIC_ADDRESS,
3859 MGMT_STATUS_INVALID_PARAMS);
3860
3861 /* Two most significant bits shall be set */
3862 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3863 return cmd_status(sk, hdev->id,
3864 MGMT_OP_SET_STATIC_ADDRESS,
3865 MGMT_STATUS_INVALID_PARAMS);
3866 }
3867
3868 hci_dev_lock(hdev);
3869
3870 bacpy(&hdev->static_addr, &cp->bdaddr);
3871
3872 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3873
3874 hci_dev_unlock(hdev);
3875
3876 return err;
3877}
3878
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003879static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3880 void *data, u16 len)
3881{
3882 struct mgmt_cp_set_scan_params *cp = data;
3883 __u16 interval, window;
3884 int err;
3885
3886 BT_DBG("%s", hdev->name);
3887
3888 if (!lmp_le_capable(hdev))
3889 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3890 MGMT_STATUS_NOT_SUPPORTED);
3891
3892 interval = __le16_to_cpu(cp->interval);
3893
3894 if (interval < 0x0004 || interval > 0x4000)
3895 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3896 MGMT_STATUS_INVALID_PARAMS);
3897
3898 window = __le16_to_cpu(cp->window);
3899
3900 if (window < 0x0004 || window > 0x4000)
3901 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3902 MGMT_STATUS_INVALID_PARAMS);
3903
Marcel Holtmann899e1072013-10-14 09:55:32 -07003904 if (window > interval)
3905 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3906 MGMT_STATUS_INVALID_PARAMS);
3907
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003908 hci_dev_lock(hdev);
3909
3910 hdev->le_scan_interval = interval;
3911 hdev->le_scan_window = window;
3912
3913 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3914
3915 hci_dev_unlock(hdev);
3916
3917 return err;
3918}
3919
Johan Hedberg33e38b32013-03-15 17:07:05 -05003920static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3921{
3922 struct pending_cmd *cmd;
3923
3924 BT_DBG("status 0x%02x", status);
3925
3926 hci_dev_lock(hdev);
3927
3928 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3929 if (!cmd)
3930 goto unlock;
3931
3932 if (status) {
3933 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3934 mgmt_status(status));
3935 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003936 struct mgmt_mode *cp = cmd->param;
3937
3938 if (cp->val)
3939 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3940 else
3941 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3942
Johan Hedberg33e38b32013-03-15 17:07:05 -05003943 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3944 new_settings(hdev, cmd->sk);
3945 }
3946
3947 mgmt_pending_remove(cmd);
3948
3949unlock:
3950 hci_dev_unlock(hdev);
3951}
3952
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003953static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003954 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003955{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003956 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003957 struct pending_cmd *cmd;
3958 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003959 int err;
3960
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003961 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003962
Johan Hedberg56f87902013-10-02 13:43:13 +03003963 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3964 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003965 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3966 MGMT_STATUS_NOT_SUPPORTED);
3967
Johan Hedberga7e80f22013-01-09 16:05:19 +02003968 if (cp->val != 0x00 && cp->val != 0x01)
3969 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3970 MGMT_STATUS_INVALID_PARAMS);
3971
Johan Hedberg5400c042012-02-21 16:40:33 +02003972 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003973 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003974 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003975
3976 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003977 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003978 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003979
3980 hci_dev_lock(hdev);
3981
Johan Hedberg05cbf292013-03-15 17:07:07 -05003982 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3983 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3984 MGMT_STATUS_BUSY);
3985 goto unlock;
3986 }
3987
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003988 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3989 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3990 hdev);
3991 goto unlock;
3992 }
3993
Johan Hedberg33e38b32013-03-15 17:07:05 -05003994 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3995 data, len);
3996 if (!cmd) {
3997 err = -ENOMEM;
3998 goto unlock;
3999 }
4000
4001 hci_req_init(&req, hdev);
4002
Johan Hedberg406d7802013-03-15 17:07:09 -05004003 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004004
4005 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004006 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004007 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004008 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004009 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004010 }
4011
Johan Hedberg33e38b32013-03-15 17:07:05 -05004012unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004013 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004014
Antti Julkuf6422ec2011-06-22 13:11:56 +03004015 return err;
4016}
4017
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03004018static void set_bredr_scan(struct hci_request *req)
4019{
4020 struct hci_dev *hdev = req->hdev;
4021 u8 scan = 0;
4022
4023 /* Ensure that fast connectable is disabled. This function will
4024 * not do anything if the page scan parameters are already what
4025 * they should be.
4026 */
4027 write_fast_connectable(req, false);
4028
4029 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4030 scan |= SCAN_PAGE;
4031 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4032 scan |= SCAN_INQUIRY;
4033
4034 if (scan)
4035 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
4036}
4037
Johan Hedberg0663ca22013-10-02 13:43:14 +03004038static void set_bredr_complete(struct hci_dev *hdev, u8 status)
4039{
4040 struct pending_cmd *cmd;
4041
4042 BT_DBG("status 0x%02x", status);
4043
4044 hci_dev_lock(hdev);
4045
4046 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
4047 if (!cmd)
4048 goto unlock;
4049
4050 if (status) {
4051 u8 mgmt_err = mgmt_status(status);
4052
4053 /* We need to restore the flag if related HCI commands
4054 * failed.
4055 */
4056 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4057
4058 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
4059 } else {
4060 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4061 new_settings(hdev, cmd->sk);
4062 }
4063
4064 mgmt_pending_remove(cmd);
4065
4066unlock:
4067 hci_dev_unlock(hdev);
4068}
4069
4070static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4071{
4072 struct mgmt_mode *cp = data;
4073 struct pending_cmd *cmd;
4074 struct hci_request req;
4075 int err;
4076
4077 BT_DBG("request for %s", hdev->name);
4078
4079 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
4080 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4081 MGMT_STATUS_NOT_SUPPORTED);
4082
4083 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
4084 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4085 MGMT_STATUS_REJECTED);
4086
4087 if (cp->val != 0x00 && cp->val != 0x01)
4088 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4089 MGMT_STATUS_INVALID_PARAMS);
4090
4091 hci_dev_lock(hdev);
4092
4093 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4094 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4095 goto unlock;
4096 }
4097
4098 if (!hdev_is_powered(hdev)) {
4099 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004100 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4101 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4102 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4103 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
4104 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
4105 }
4106
4107 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4108
4109 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4110 if (err < 0)
4111 goto unlock;
4112
4113 err = new_settings(hdev, sk);
4114 goto unlock;
4115 }
4116
4117 /* Reject disabling when powered on */
4118 if (!cp->val) {
4119 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4120 MGMT_STATUS_REJECTED);
4121 goto unlock;
4122 }
4123
4124 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
4125 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4126 MGMT_STATUS_BUSY);
4127 goto unlock;
4128 }
4129
4130 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4131 if (!cmd) {
4132 err = -ENOMEM;
4133 goto unlock;
4134 }
4135
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004136 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03004137 * generates the correct flags.
4138 */
4139 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4140
4141 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004142
4143 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4144 set_bredr_scan(&req);
4145
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004146 /* Since only the advertising data flags will change, there
4147 * is no need to update the scan response data.
4148 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004149 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004150
Johan Hedberg0663ca22013-10-02 13:43:14 +03004151 err = hci_req_run(&req, set_bredr_complete);
4152 if (err < 0)
4153 mgmt_pending_remove(cmd);
4154
4155unlock:
4156 hci_dev_unlock(hdev);
4157 return err;
4158}
4159
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004160static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4161 void *data, u16 len)
4162{
4163 struct mgmt_mode *cp = data;
4164 struct pending_cmd *cmd;
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004165 u8 val, status;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004166 int err;
4167
4168 BT_DBG("request for %s", hdev->name);
4169
4170 status = mgmt_bredr_support(hdev);
4171 if (status)
4172 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4173 status);
4174
Marcel Holtmann5afeac12014-01-10 02:07:27 -08004175 if (!lmp_sc_capable(hdev) &&
4176 !test_bit(HCI_FORCE_SC, &hdev->dev_flags))
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004177 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4178 MGMT_STATUS_NOT_SUPPORTED);
4179
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004180 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004181 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4182 MGMT_STATUS_INVALID_PARAMS);
4183
4184 hci_dev_lock(hdev);
4185
4186 if (!hdev_is_powered(hdev)) {
4187 bool changed;
4188
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004189 if (cp->val) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004190 changed = !test_and_set_bit(HCI_SC_ENABLED,
4191 &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004192 if (cp->val == 0x02)
4193 set_bit(HCI_SC_ONLY, &hdev->dev_flags);
4194 else
4195 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4196 } else {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004197 changed = test_and_clear_bit(HCI_SC_ENABLED,
4198 &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004199 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4200 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004201
4202 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4203 if (err < 0)
4204 goto failed;
4205
4206 if (changed)
4207 err = new_settings(hdev, sk);
4208
4209 goto failed;
4210 }
4211
4212 if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
4213 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4214 MGMT_STATUS_BUSY);
4215 goto failed;
4216 }
4217
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004218 val = !!cp->val;
4219
4220 if (val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
4221 (cp->val == 0x02) == test_bit(HCI_SC_ONLY, &hdev->dev_flags)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004222 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4223 goto failed;
4224 }
4225
4226 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4227 if (!cmd) {
4228 err = -ENOMEM;
4229 goto failed;
4230 }
4231
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004232 err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004233 if (err < 0) {
4234 mgmt_pending_remove(cmd);
4235 goto failed;
4236 }
4237
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004238 if (cp->val == 0x02)
4239 set_bit(HCI_SC_ONLY, &hdev->dev_flags);
4240 else
4241 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4242
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004243failed:
4244 hci_dev_unlock(hdev);
4245 return err;
4246}
4247
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004248static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4249 void *data, u16 len)
4250{
4251 struct mgmt_mode *cp = data;
4252 bool changed;
4253 int err;
4254
4255 BT_DBG("request for %s", hdev->name);
4256
4257 if (cp->val != 0x00 && cp->val != 0x01)
4258 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4259 MGMT_STATUS_INVALID_PARAMS);
4260
4261 hci_dev_lock(hdev);
4262
4263 if (cp->val)
4264 changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
4265 else
4266 changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
4267
4268 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4269 if (err < 0)
4270 goto unlock;
4271
4272 if (changed)
4273 err = new_settings(hdev, sk);
4274
4275unlock:
4276 hci_dev_unlock(hdev);
4277 return err;
4278}
4279
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004280static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4281 u16 len)
4282{
4283 struct mgmt_cp_set_privacy *cp = cp_data;
4284 bool changed;
4285 int err;
4286
4287 BT_DBG("request for %s", hdev->name);
4288
4289 if (!lmp_le_capable(hdev))
4290 return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4291 MGMT_STATUS_NOT_SUPPORTED);
4292
4293 if (cp->privacy != 0x00 && cp->privacy != 0x01)
4294 return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4295 MGMT_STATUS_INVALID_PARAMS);
4296
4297 if (hdev_is_powered(hdev))
4298 return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4299 MGMT_STATUS_REJECTED);
4300
4301 hci_dev_lock(hdev);
4302
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004303 /* If user space supports this command it is also expected to
4304 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4305 */
4306 set_bit(HCI_RPA_RESOLVING, &hdev->dev_flags);
4307
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004308 if (cp->privacy) {
4309 changed = !test_and_set_bit(HCI_PRIVACY, &hdev->dev_flags);
4310 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
4311 set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
4312 } else {
4313 changed = test_and_clear_bit(HCI_PRIVACY, &hdev->dev_flags);
4314 memset(hdev->irk, 0, sizeof(hdev->irk));
4315 clear_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
4316 }
4317
4318 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4319 if (err < 0)
4320 goto unlock;
4321
4322 if (changed)
4323 err = new_settings(hdev, sk);
4324
4325unlock:
4326 hci_dev_unlock(hdev);
4327 return err;
4328}
4329
Johan Hedberg41edf162014-02-18 10:19:35 +02004330static bool irk_is_valid(struct mgmt_irk_info *irk)
4331{
4332 switch (irk->addr.type) {
4333 case BDADDR_LE_PUBLIC:
4334 return true;
4335
4336 case BDADDR_LE_RANDOM:
4337 /* Two most significant bits shall be set */
4338 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4339 return false;
4340 return true;
4341 }
4342
4343 return false;
4344}
4345
4346static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4347 u16 len)
4348{
4349 struct mgmt_cp_load_irks *cp = cp_data;
4350 u16 irk_count, expected_len;
4351 int i, err;
4352
4353 BT_DBG("request for %s", hdev->name);
4354
4355 if (!lmp_le_capable(hdev))
4356 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4357 MGMT_STATUS_NOT_SUPPORTED);
4358
4359 irk_count = __le16_to_cpu(cp->irk_count);
4360
4361 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4362 if (expected_len != len) {
4363 BT_ERR("load_irks: expected %u bytes, got %u bytes",
4364 len, expected_len);
4365 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4366 MGMT_STATUS_INVALID_PARAMS);
4367 }
4368
4369 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4370
4371 for (i = 0; i < irk_count; i++) {
4372 struct mgmt_irk_info *key = &cp->irks[i];
4373
4374 if (!irk_is_valid(key))
4375 return cmd_status(sk, hdev->id,
4376 MGMT_OP_LOAD_IRKS,
4377 MGMT_STATUS_INVALID_PARAMS);
4378 }
4379
4380 hci_dev_lock(hdev);
4381
4382 hci_smp_irks_clear(hdev);
4383
4384 for (i = 0; i < irk_count; i++) {
4385 struct mgmt_irk_info *irk = &cp->irks[i];
4386 u8 addr_type;
4387
4388 if (irk->addr.type == BDADDR_LE_PUBLIC)
4389 addr_type = ADDR_LE_DEV_PUBLIC;
4390 else
4391 addr_type = ADDR_LE_DEV_RANDOM;
4392
4393 hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
4394 BDADDR_ANY);
4395 }
4396
4397 set_bit(HCI_RPA_RESOLVING, &hdev->dev_flags);
4398
4399 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
4400
4401 hci_dev_unlock(hdev);
4402
4403 return err;
4404}
4405
Johan Hedberg3f706b72013-01-20 14:27:16 +02004406static bool ltk_is_valid(struct mgmt_ltk_info *key)
4407{
4408 if (key->master != 0x00 && key->master != 0x01)
4409 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004410
4411 switch (key->addr.type) {
4412 case BDADDR_LE_PUBLIC:
4413 return true;
4414
4415 case BDADDR_LE_RANDOM:
4416 /* Two most significant bits shall be set */
4417 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4418 return false;
4419 return true;
4420 }
4421
4422 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004423}
4424
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004425static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004426 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004427{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004428 struct mgmt_cp_load_long_term_keys *cp = cp_data;
4429 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004430 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004431
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004432 BT_DBG("request for %s", hdev->name);
4433
4434 if (!lmp_le_capable(hdev))
4435 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4436 MGMT_STATUS_NOT_SUPPORTED);
4437
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004438 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004439
4440 expected_len = sizeof(*cp) + key_count *
4441 sizeof(struct mgmt_ltk_info);
4442 if (expected_len != len) {
4443 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004444 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004445 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02004446 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004447 }
4448
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004449 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004450
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004451 for (i = 0; i < key_count; i++) {
4452 struct mgmt_ltk_info *key = &cp->keys[i];
4453
Johan Hedberg3f706b72013-01-20 14:27:16 +02004454 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004455 return cmd_status(sk, hdev->id,
4456 MGMT_OP_LOAD_LONG_TERM_KEYS,
4457 MGMT_STATUS_INVALID_PARAMS);
4458 }
4459
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004460 hci_dev_lock(hdev);
4461
4462 hci_smp_ltks_clear(hdev);
4463
4464 for (i = 0; i < key_count; i++) {
4465 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004466 u8 type, addr_type;
4467
4468 if (key->addr.type == BDADDR_LE_PUBLIC)
4469 addr_type = ADDR_LE_DEV_PUBLIC;
4470 else
4471 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004472
4473 if (key->master)
4474 type = HCI_SMP_LTK;
4475 else
4476 type = HCI_SMP_LTK_SLAVE;
4477
Johan Hedberg35d70272014-02-19 14:57:47 +02004478 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type,
4479 key->type, key->val, key->enc_size, key->ediv,
4480 key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004481 }
4482
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004483 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4484 NULL, 0);
4485
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004486 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004487
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004488 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004489}
4490
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004491static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004492 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4493 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004494 bool var_len;
4495 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004496} mgmt_handlers[] = {
4497 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004498 { read_version, false, MGMT_READ_VERSION_SIZE },
4499 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4500 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4501 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4502 { set_powered, false, MGMT_SETTING_SIZE },
4503 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4504 { set_connectable, false, MGMT_SETTING_SIZE },
4505 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4506 { set_pairable, false, MGMT_SETTING_SIZE },
4507 { set_link_security, false, MGMT_SETTING_SIZE },
4508 { set_ssp, false, MGMT_SETTING_SIZE },
4509 { set_hs, false, MGMT_SETTING_SIZE },
4510 { set_le, false, MGMT_SETTING_SIZE },
4511 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4512 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4513 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4514 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4515 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4516 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4517 { disconnect, false, MGMT_DISCONNECT_SIZE },
4518 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4519 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4520 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4521 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4522 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4523 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4524 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4525 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4526 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4527 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4528 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4529 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
Marcel Holtmannec109112014-01-10 02:07:30 -08004530 { add_remote_oob_data, true, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
Johan Hedbergbe22b542012-03-01 22:24:41 +02004531 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4532 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4533 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4534 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4535 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4536 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004537 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004538 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004539 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004540 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004541 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004542 { set_secure_conn, false, MGMT_SETTING_SIZE },
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004543 { set_debug_keys, false, MGMT_SETTING_SIZE },
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004544 { set_privacy, false, MGMT_SET_PRIVACY_SIZE },
Johan Hedberg41edf162014-02-18 10:19:35 +02004545 { load_irks, true, MGMT_LOAD_IRKS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004546};
4547
4548
Johan Hedberg03811012010-12-08 00:21:06 +02004549int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4550{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004551 void *buf;
4552 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004553 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004554 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004555 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004556 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004557 int err;
4558
4559 BT_DBG("got %zu bytes", msglen);
4560
4561 if (msglen < sizeof(*hdr))
4562 return -EINVAL;
4563
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004564 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004565 if (!buf)
4566 return -ENOMEM;
4567
4568 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4569 err = -EFAULT;
4570 goto done;
4571 }
4572
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004573 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004574 opcode = __le16_to_cpu(hdr->opcode);
4575 index = __le16_to_cpu(hdr->index);
4576 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004577
4578 if (len != msglen - sizeof(*hdr)) {
4579 err = -EINVAL;
4580 goto done;
4581 }
4582
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004583 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004584 hdev = hci_dev_get(index);
4585 if (!hdev) {
4586 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004587 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004588 goto done;
4589 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004590
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004591 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4592 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004593 err = cmd_status(sk, index, opcode,
4594 MGMT_STATUS_INVALID_INDEX);
4595 goto done;
4596 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004597 }
4598
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004599 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004600 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004601 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004602 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004603 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004604 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004605 }
4606
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004607 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004608 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004609 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004610 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004611 goto done;
4612 }
4613
Johan Hedbergbe22b542012-03-01 22:24:41 +02004614 handler = &mgmt_handlers[opcode];
4615
4616 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004617 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004618 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004619 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004620 goto done;
4621 }
4622
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004623 if (hdev)
4624 mgmt_init_hdev(sk, hdev);
4625
4626 cp = buf + sizeof(*hdr);
4627
Johan Hedbergbe22b542012-03-01 22:24:41 +02004628 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004629 if (err < 0)
4630 goto done;
4631
Johan Hedberg03811012010-12-08 00:21:06 +02004632 err = msglen;
4633
4634done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004635 if (hdev)
4636 hci_dev_put(hdev);
4637
Johan Hedberg03811012010-12-08 00:21:06 +02004638 kfree(buf);
4639 return err;
4640}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004641
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004642void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004643{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004644 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004645 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004646
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004647 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004648}
4649
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004650void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004651{
Johan Hedberg5f159032012-03-02 03:13:19 +02004652 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +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
Johan Hedberg744cf192011-11-08 20:40:14 +02004657 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004658
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004659 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004660}
4661
Johan Hedberg229ab392013-03-15 17:06:53 -05004662static void powered_complete(struct hci_dev *hdev, u8 status)
4663{
4664 struct cmd_lookup match = { NULL, hdev };
4665
4666 BT_DBG("status 0x%02x", status);
4667
4668 hci_dev_lock(hdev);
4669
4670 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4671
4672 new_settings(hdev, match.sk);
4673
4674 hci_dev_unlock(hdev);
4675
4676 if (match.sk)
4677 sock_put(match.sk);
4678}
4679
Johan Hedberg70da6242013-03-15 17:06:51 -05004680static int powered_update_hci(struct hci_dev *hdev)
4681{
Johan Hedberg890ea892013-03-15 17:06:52 -05004682 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004683 u8 link_sec;
4684
Johan Hedberg890ea892013-03-15 17:06:52 -05004685 hci_req_init(&req, hdev);
4686
Johan Hedberg70da6242013-03-15 17:06:51 -05004687 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4688 !lmp_host_ssp_capable(hdev)) {
4689 u8 ssp = 1;
4690
Johan Hedberg890ea892013-03-15 17:06:52 -05004691 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004692 }
4693
Johan Hedbergc73eee92013-04-19 18:35:21 +03004694 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4695 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004696 struct hci_cp_write_le_host_supported cp;
4697
4698 cp.le = 1;
4699 cp.simul = lmp_le_br_capable(hdev);
4700
4701 /* Check first if we already have the right
4702 * host state (host features set)
4703 */
4704 if (cp.le != lmp_host_le_capable(hdev) ||
4705 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004706 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4707 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004708 }
4709
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004710 if (lmp_le_capable(hdev)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004711 /* Make sure the controller has a good default for
4712 * advertising data. This also applies to the case
4713 * where BR/EDR was toggled during the AUTO_OFF phase.
4714 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004715 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004716 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004717 update_scan_rsp_data(&req);
4718 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004719
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004720 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4721 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004722 }
4723
Johan Hedberg70da6242013-03-15 17:06:51 -05004724 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4725 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004726 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4727 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004728
4729 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004730 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4731 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004732 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004733 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004734 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004735 }
4736
Johan Hedberg229ab392013-03-15 17:06:53 -05004737 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004738}
4739
Johan Hedberg744cf192011-11-08 20:40:14 +02004740int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004741{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004742 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004743 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4744 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004745 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004746
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004747 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4748 return 0;
4749
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004750 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004751 if (powered_update_hci(hdev) == 0)
4752 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004753
Johan Hedberg229ab392013-03-15 17:06:53 -05004754 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4755 &match);
4756 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004757 }
4758
Johan Hedberg229ab392013-03-15 17:06:53 -05004759 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4760 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4761
4762 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4763 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4764 zero_cod, sizeof(zero_cod), NULL);
4765
4766new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004767 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004768
4769 if (match.sk)
4770 sock_put(match.sk);
4771
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004772 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004773}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004774
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004775void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004776{
4777 struct pending_cmd *cmd;
4778 u8 status;
4779
4780 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4781 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004782 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004783
4784 if (err == -ERFKILL)
4785 status = MGMT_STATUS_RFKILLED;
4786 else
4787 status = MGMT_STATUS_FAILED;
4788
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004789 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004790
4791 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004792}
4793
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004794void mgmt_discoverable_timeout(struct hci_dev *hdev)
4795{
4796 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004797
4798 hci_dev_lock(hdev);
4799
4800 /* When discoverable timeout triggers, then just make sure
4801 * the limited discoverable flag is cleared. Even in the case
4802 * of a timeout triggered from general discoverable, it is
4803 * safe to unconditionally clear the flag.
4804 */
4805 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004806 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004807
4808 hci_req_init(&req, hdev);
Johan Hedberg4b580612013-10-19 23:38:21 +03004809 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4810 u8 scan = SCAN_PAGE;
4811 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
4812 sizeof(scan), &scan);
4813 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004814 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004815 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004816 hci_req_run(&req, NULL);
4817
4818 hdev->discov_timeout = 0;
4819
Johan Hedberg9a43e252013-10-20 19:00:07 +03004820 new_settings(hdev, NULL);
4821
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004822 hci_dev_unlock(hdev);
4823}
4824
Marcel Holtmann86a75642013-10-15 06:33:54 -07004825void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004826{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004827 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004828
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004829 /* Nothing needed here if there's a pending command since that
4830 * commands request completion callback takes care of everything
4831 * necessary.
4832 */
4833 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004834 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004835
Johan Hedbergbd107992014-02-24 14:52:19 +02004836 /* Powering off may clear the scan mode - don't let that interfere */
4837 if (!discoverable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4838 return;
4839
Johan Hedberg9a43e252013-10-20 19:00:07 +03004840 if (discoverable) {
Marcel Holtmann86a75642013-10-15 06:33:54 -07004841 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004842 } else {
4843 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmann86a75642013-10-15 06:33:54 -07004844 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004845 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004846
Johan Hedberg9a43e252013-10-20 19:00:07 +03004847 if (changed) {
4848 struct hci_request req;
4849
4850 /* In case this change in discoverable was triggered by
4851 * a disabling of connectable there could be a need to
4852 * update the advertising flags.
4853 */
4854 hci_req_init(&req, hdev);
4855 update_adv_data(&req);
4856 hci_req_run(&req, NULL);
4857
Marcel Holtmann86a75642013-10-15 06:33:54 -07004858 new_settings(hdev, NULL);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004859 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004860}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004861
Marcel Holtmanna3309162013-10-15 06:33:55 -07004862void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004863{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004864 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004865
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004866 /* Nothing needed here if there's a pending command since that
4867 * commands request completion callback takes care of everything
4868 * necessary.
4869 */
4870 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004871 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004872
Johan Hedbergce3f24c2014-02-24 14:52:20 +02004873 /* Powering off may clear the scan mode - don't let that interfere */
4874 if (!connectable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4875 return;
4876
Marcel Holtmanna3309162013-10-15 06:33:55 -07004877 if (connectable)
4878 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4879 else
4880 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004881
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004882 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004883 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004884}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004885
Johan Hedberg778b2352014-02-24 14:52:17 +02004886void mgmt_advertising(struct hci_dev *hdev, u8 advertising)
4887{
Johan Hedberg7c4cfab2014-02-24 14:52:21 +02004888 /* Powering off may stop advertising - don't let that interfere */
4889 if (!advertising && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4890 return;
4891
Johan Hedberg778b2352014-02-24 14:52:17 +02004892 if (advertising)
4893 set_bit(HCI_ADVERTISING, &hdev->dev_flags);
4894 else
4895 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
4896}
4897
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004898void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004899{
Johan Hedbergca69b792011-11-11 18:10:00 +02004900 u8 mgmt_err = mgmt_status(status);
4901
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004902 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004903 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004904 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004905
4906 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004907 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004908 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004909}
4910
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004911void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4912 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004913{
Johan Hedberg86742e12011-11-07 23:13:38 +02004914 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004915
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004916 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004917
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004918 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004919 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004920 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004921 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004922 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004923 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004924
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004925 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004926}
Johan Hedbergf7520542011-01-20 12:34:39 +02004927
Johan Hedbergba74b662014-02-19 14:57:45 +02004928void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004929{
4930 struct mgmt_ev_new_long_term_key ev;
4931
4932 memset(&ev, 0, sizeof(ev));
4933
Marcel Holtmann5192d302014-02-19 17:11:58 -08004934 /* Devices using resolvable or non-resolvable random addresses
4935 * without providing an indentity resolving key don't require
4936 * to store long term keys. Their addresses will change the
4937 * next time around.
4938 *
4939 * Only when a remote device provides an identity address
4940 * make sure the long term key is stored. If the remote
4941 * identity is known, the long term keys are internally
4942 * mapped to the identity address. So allow static random
4943 * and public addresses here.
4944 */
Johan Hedbergba74b662014-02-19 14:57:45 +02004945 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
4946 (key->bdaddr.b[5] & 0xc0) != 0xc0)
4947 ev.store_hint = 0x00;
4948 else
4949 ev.store_hint = 0x01;
4950
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004951 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004952 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Marcel Holtmannd40f3ee2014-01-31 18:42:17 -08004953 ev.key.type = key->authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004954 ev.key.enc_size = key->enc_size;
4955 ev.key.ediv = key->ediv;
4956
4957 if (key->type == HCI_SMP_LTK)
4958 ev.key.master = 1;
4959
4960 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4961 memcpy(ev.key.val, key->val, sizeof(key->val));
4962
Marcel Holtmann083368f2013-10-15 14:26:29 -07004963 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004964}
4965
Johan Hedberg95fbac82014-02-19 15:18:31 +02004966void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk)
4967{
4968 struct mgmt_ev_new_irk ev;
4969
4970 memset(&ev, 0, sizeof(ev));
4971
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08004972 /* For identity resolving keys from devices that are already
4973 * using a public address or static random address, do not
4974 * ask for storing this key. The identity resolving key really
4975 * is only mandatory for devices using resovlable random
4976 * addresses.
4977 *
4978 * Storing all identity resolving keys has the downside that
4979 * they will be also loaded on next boot of they system. More
4980 * identity resolving keys, means more time during scanning is
4981 * needed to actually resolve these addresses.
4982 */
4983 if (bacmp(&irk->rpa, BDADDR_ANY))
4984 ev.store_hint = 0x01;
4985 else
4986 ev.store_hint = 0x00;
4987
Johan Hedberg95fbac82014-02-19 15:18:31 +02004988 bacpy(&ev.rpa, &irk->rpa);
4989 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
4990 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
4991 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
4992
4993 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
4994}
4995
Marcel Holtmann94933992013-10-15 10:26:39 -07004996static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4997 u8 data_len)
4998{
4999 eir[eir_len++] = sizeof(type) + data_len;
5000 eir[eir_len++] = type;
5001 memcpy(&eir[eir_len], data, data_len);
5002 eir_len += data_len;
5003
5004 return eir_len;
5005}
5006
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07005007void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5008 u8 addr_type, u32 flags, u8 *name, u8 name_len,
5009 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02005010{
Johan Hedbergb644ba32012-01-17 21:48:47 +02005011 char buf[512];
5012 struct mgmt_ev_device_connected *ev = (void *) buf;
5013 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02005014
Johan Hedbergb644ba32012-01-17 21:48:47 +02005015 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005016 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02005017
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02005018 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02005019
Johan Hedbergb644ba32012-01-17 21:48:47 +02005020 if (name_len > 0)
5021 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005022 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005023
5024 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08005025 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005026 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005027
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005028 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005029
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07005030 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
5031 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02005032}
5033
Johan Hedberg8962ee72011-01-20 12:40:27 +02005034static void disconnect_rsp(struct pending_cmd *cmd, void *data)
5035{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01005036 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005037 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02005038 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005039
Johan Hedberg88c3df12012-02-09 14:27:38 +02005040 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5041 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005042
Johan Hedbergaee9b212012-02-18 15:07:59 +02005043 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005044 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02005045
5046 *sk = cmd->sk;
5047 sock_hold(*sk);
5048
Johan Hedberga664b5b2011-02-19 12:06:02 -03005049 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005050}
5051
Johan Hedberg124f6e32012-02-09 13:50:12 +02005052static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02005053{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02005054 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02005055 struct mgmt_cp_unpair_device *cp = cmd->param;
5056 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02005057
5058 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02005059 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5060 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02005061
Johan Hedbergb1078ad2012-02-09 17:21:16 +02005062 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
5063
Johan Hedbergaee9b212012-02-18 15:07:59 +02005064 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02005065
5066 mgmt_pending_remove(cmd);
5067}
5068
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07005069void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02005070 u8 link_type, u8 addr_type, u8 reason,
5071 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02005072{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02005073 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8b064a32014-02-24 14:52:22 +02005074 struct pending_cmd *power_off;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005075 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005076
Johan Hedberg8b064a32014-02-24 14:52:22 +02005077 power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
5078 if (power_off) {
5079 struct mgmt_mode *cp = power_off->param;
5080
5081 /* The connection is still in hci_conn_hash so test for 1
5082 * instead of 0 to know if this is the last one.
5083 */
5084 if (!cp->val && hci_conn_count(hdev) == 1)
5085 queue_work(hdev->req_workqueue, &hdev->power_off.work);
5086 }
5087
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02005088 if (!mgmt_connected)
5089 return;
5090
Andre Guedes57eb7762013-10-30 19:01:41 -03005091 if (link_type != ACL_LINK && link_type != LE_LINK)
5092 return;
5093
Johan Hedberg744cf192011-11-08 20:40:14 +02005094 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02005095
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02005096 bacpy(&ev.addr.bdaddr, bdaddr);
5097 ev.addr.type = link_to_bdaddr(link_type, addr_type);
5098 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02005099
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07005100 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005101
5102 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01005103 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005104
Johan Hedberg124f6e32012-02-09 13:50:12 +02005105 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005106 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005107}
5108
Marcel Holtmann78929242013-10-06 23:55:47 -07005109void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
5110 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02005111{
Andre Guedes3655bba2013-10-30 19:01:40 -03005112 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
5113 struct mgmt_cp_disconnect *cp;
Johan Hedberg88c3df12012-02-09 14:27:38 +02005114 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005115 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005116
Jefferson Delfes36a75f12012-09-18 13:36:54 -04005117 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
5118 hdev);
5119
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005120 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005121 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07005122 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005123
Andre Guedes3655bba2013-10-30 19:01:40 -03005124 cp = cmd->param;
5125
5126 if (bacmp(bdaddr, &cp->addr.bdaddr))
5127 return;
5128
5129 if (cp->addr.type != bdaddr_type)
5130 return;
5131
Johan Hedberg88c3df12012-02-09 14:27:38 +02005132 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes3655bba2013-10-30 19:01:40 -03005133 rp.addr.type = bdaddr_type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02005134
Marcel Holtmann78929242013-10-06 23:55:47 -07005135 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
5136 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02005137
Johan Hedberga664b5b2011-02-19 12:06:02 -03005138 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02005139}
Johan Hedberg17d5c042011-01-22 06:09:08 +02005140
Marcel Holtmann445608d2013-10-06 23:55:48 -07005141void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5142 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02005143{
5144 struct mgmt_ev_connect_failed ev;
5145
Johan Hedberg4c659c32011-11-07 23:13:39 +02005146 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005147 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02005148 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02005149
Marcel Holtmann445608d2013-10-06 23:55:48 -07005150 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02005151}
Johan Hedberg980e1a52011-01-22 06:10:07 +02005152
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07005153void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02005154{
5155 struct mgmt_ev_pin_code_request ev;
5156
Johan Hedbergd8457692012-02-17 14:24:57 +02005157 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03005158 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02005159 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005160
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07005161 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005162}
5163
Marcel Holtmanne669cf82013-10-15 14:26:21 -07005164void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
5165 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02005166{
5167 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005168 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005169
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005170 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005171 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07005172 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005173
Johan Hedbergd8457692012-02-17 14:24:57 +02005174 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03005175 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005176
Marcel Holtmanne669cf82013-10-15 14:26:21 -07005177 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
5178 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02005179
Johan Hedberga664b5b2011-02-19 12:06:02 -03005180 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005181}
5182
Marcel Holtmann3eb38522013-10-15 14:26:22 -07005183void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
5184 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02005185{
5186 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005187 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005188
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005189 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005190 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07005191 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005192
Johan Hedbergd8457692012-02-17 14:24:57 +02005193 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03005194 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005195
Marcel Holtmann3eb38522013-10-15 14:26:22 -07005196 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
5197 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02005198
Johan Hedberga664b5b2011-02-19 12:06:02 -03005199 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005200}
Johan Hedberga5c29682011-02-19 12:05:57 -03005201
Johan Hedberg744cf192011-11-08 20:40:14 +02005202int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005203 u8 link_type, u8 addr_type, __le32 value,
5204 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03005205{
5206 struct mgmt_ev_user_confirm_request ev;
5207
Johan Hedberg744cf192011-11-08 20:40:14 +02005208 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03005209
Johan Hedberg272d90d2012-02-09 15:26:12 +02005210 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005211 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07005212 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02005213 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03005214
Johan Hedberg744cf192011-11-08 20:40:14 +02005215 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005216 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03005217}
5218
Johan Hedberg272d90d2012-02-09 15:26:12 +02005219int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03005220 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08005221{
5222 struct mgmt_ev_user_passkey_request ev;
5223
5224 BT_DBG("%s", hdev->name);
5225
Johan Hedberg272d90d2012-02-09 15:26:12 +02005226 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005227 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08005228
5229 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005230 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08005231}
5232
Brian Gix0df4c182011-11-16 13:53:13 -08005233static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03005234 u8 link_type, u8 addr_type, u8 status,
5235 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03005236{
5237 struct pending_cmd *cmd;
5238 struct mgmt_rp_user_confirm_reply rp;
5239 int err;
5240
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005241 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03005242 if (!cmd)
5243 return -ENOENT;
5244
Johan Hedberg272d90d2012-02-09 15:26:12 +02005245 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005246 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02005247 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005248 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03005249
Johan Hedberga664b5b2011-02-19 12:06:02 -03005250 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03005251
5252 return err;
5253}
5254
Johan Hedberg744cf192011-11-08 20:40:14 +02005255int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005256 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03005257{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005258 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005259 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03005260}
5261
Johan Hedberg272d90d2012-02-09 15:26:12 +02005262int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005263 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03005264{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005265 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03005266 status,
5267 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03005268}
Johan Hedberg2a611692011-02-19 12:06:00 -03005269
Brian Gix604086b2011-11-23 08:28:33 -08005270int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005271 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08005272{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005273 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005274 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08005275}
5276
Johan Hedberg272d90d2012-02-09 15:26:12 +02005277int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005278 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08005279{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005280 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03005281 status,
5282 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08005283}
5284
Johan Hedberg92a25252012-09-06 18:39:26 +03005285int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
5286 u8 link_type, u8 addr_type, u32 passkey,
5287 u8 entered)
5288{
5289 struct mgmt_ev_passkey_notify ev;
5290
5291 BT_DBG("%s", hdev->name);
5292
5293 bacpy(&ev.addr.bdaddr, bdaddr);
5294 ev.addr.type = link_to_bdaddr(link_type, addr_type);
5295 ev.passkey = __cpu_to_le32(passkey);
5296 ev.entered = entered;
5297
5298 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
5299}
5300
Marcel Holtmanne5460992013-10-15 14:26:23 -07005301void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5302 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03005303{
5304 struct mgmt_ev_auth_failed ev;
5305
Johan Hedbergbab73cb2012-02-09 16:07:29 +02005306 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005307 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02005308 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03005309
Marcel Holtmanne5460992013-10-15 14:26:23 -07005310 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03005311}
Johan Hedbergb312b1612011-03-16 14:29:37 +02005312
Marcel Holtmann464996a2013-10-15 14:26:24 -07005313void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005314{
5315 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07005316 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005317
5318 if (status) {
5319 u8 mgmt_err = mgmt_status(status);
5320 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005321 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07005322 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005323 }
5324
Marcel Holtmann464996a2013-10-15 14:26:24 -07005325 if (test_bit(HCI_AUTH, &hdev->flags))
5326 changed = !test_and_set_bit(HCI_LINK_SECURITY,
5327 &hdev->dev_flags);
5328 else
5329 changed = test_and_clear_bit(HCI_LINK_SECURITY,
5330 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02005331
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005332 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005333 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005334
Johan Hedberg47990ea2012-02-22 11:58:37 +02005335 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07005336 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005337
5338 if (match.sk)
5339 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005340}
5341
Johan Hedberg890ea892013-03-15 17:06:52 -05005342static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02005343{
Johan Hedberg890ea892013-03-15 17:06:52 -05005344 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02005345 struct hci_cp_write_eir cp;
5346
Johan Hedberg976eb202012-10-24 21:12:01 +03005347 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05005348 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02005349
Johan Hedbergc80da272012-02-22 15:38:48 +02005350 memset(hdev->eir, 0, sizeof(hdev->eir));
5351
Johan Hedbergcacaf522012-02-21 00:52:42 +02005352 memset(&cp, 0, sizeof(cp));
5353
Johan Hedberg890ea892013-03-15 17:06:52 -05005354 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02005355}
5356
Marcel Holtmann3e248562013-10-15 14:26:25 -07005357void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005358{
5359 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05005360 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005361 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005362
5363 if (status) {
5364 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005365
5366 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005367 &hdev->dev_flags)) {
5368 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07005369 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005370 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005371
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005372 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
5373 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07005374 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005375 }
5376
5377 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005378 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005379 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005380 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
5381 if (!changed)
5382 changed = test_and_clear_bit(HCI_HS_ENABLED,
5383 &hdev->dev_flags);
5384 else
5385 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005386 }
5387
5388 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
5389
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005390 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07005391 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005392
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005393 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005394 sock_put(match.sk);
5395
Johan Hedberg890ea892013-03-15 17:06:52 -05005396 hci_req_init(&req, hdev);
5397
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005398 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05005399 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005400 else
Johan Hedberg890ea892013-03-15 17:06:52 -05005401 clear_eir(&req);
5402
5403 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005404}
5405
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005406void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
5407{
5408 struct cmd_lookup match = { NULL, hdev };
5409 bool changed = false;
5410
5411 if (status) {
5412 u8 mgmt_err = mgmt_status(status);
5413
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005414 if (enable) {
5415 if (test_and_clear_bit(HCI_SC_ENABLED,
5416 &hdev->dev_flags))
5417 new_settings(hdev, NULL);
5418 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
5419 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005420
5421 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5422 cmd_status_rsp, &mgmt_err);
5423 return;
5424 }
5425
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005426 if (enable) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005427 changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005428 } else {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005429 changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005430 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
5431 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005432
5433 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5434 settings_rsp, &match);
5435
5436 if (changed)
5437 new_settings(hdev, match.sk);
5438
5439 if (match.sk)
5440 sock_put(match.sk);
5441}
5442
Johan Hedberg92da6092013-03-15 17:06:55 -05005443static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02005444{
5445 struct cmd_lookup *match = data;
5446
Johan Hedberg90e70452012-02-23 23:09:40 +02005447 if (match->sk == NULL) {
5448 match->sk = cmd->sk;
5449 sock_hold(match->sk);
5450 }
Johan Hedberg90e70452012-02-23 23:09:40 +02005451}
5452
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005453void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
5454 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005455{
Johan Hedberg90e70452012-02-23 23:09:40 +02005456 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005457
Johan Hedberg92da6092013-03-15 17:06:55 -05005458 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
5459 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
5460 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02005461
5462 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005463 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
5464 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02005465
5466 if (match.sk)
5467 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005468}
5469
Marcel Holtmann7667da32013-10-15 14:26:27 -07005470void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02005471{
Johan Hedbergb312b1612011-03-16 14:29:37 +02005472 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05005473 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005474
Johan Hedberg13928972013-03-15 17:07:00 -05005475 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07005476 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005477
5478 memset(&ev, 0, sizeof(ev));
5479 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005480 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005481
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005482 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05005483 if (!cmd) {
5484 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02005485
Johan Hedberg13928972013-03-15 17:07:00 -05005486 /* If this is a HCI command related to powering on the
5487 * HCI dev don't send any mgmt signals.
5488 */
5489 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07005490 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005491 }
5492
Marcel Holtmann7667da32013-10-15 14:26:27 -07005493 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
5494 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005495}
Szymon Jancc35938b2011-03-22 13:12:21 +01005496
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005497void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
5498 u8 *randomizer192, u8 *hash256,
5499 u8 *randomizer256, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01005500{
5501 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01005502
Johan Hedberg744cf192011-11-08 20:40:14 +02005503 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01005504
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005505 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01005506 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005507 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01005508
5509 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005510 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
5511 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01005512 } else {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005513 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
5514 hash256 && randomizer256) {
5515 struct mgmt_rp_read_local_oob_ext_data rp;
Szymon Jancc35938b2011-03-22 13:12:21 +01005516
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005517 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
5518 memcpy(rp.randomizer192, randomizer192,
5519 sizeof(rp.randomizer192));
Szymon Jancc35938b2011-03-22 13:12:21 +01005520
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005521 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
5522 memcpy(rp.randomizer256, randomizer256,
5523 sizeof(rp.randomizer256));
5524
5525 cmd_complete(cmd->sk, hdev->id,
5526 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5527 &rp, sizeof(rp));
5528 } else {
5529 struct mgmt_rp_read_local_oob_data rp;
5530
5531 memcpy(rp.hash, hash192, sizeof(rp.hash));
5532 memcpy(rp.randomizer, randomizer192,
5533 sizeof(rp.randomizer));
5534
5535 cmd_complete(cmd->sk, hdev->id,
5536 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5537 &rp, sizeof(rp));
5538 }
Szymon Jancc35938b2011-03-22 13:12:21 +01005539 }
5540
5541 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01005542}
Johan Hedberge17acd42011-03-30 23:57:16 +03005543
Marcel Holtmann901801b2013-10-06 23:55:51 -07005544void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5545 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
5546 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03005547{
Johan Hedberge319d2e2012-01-15 19:51:59 +02005548 char buf[512];
5549 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg5cedbb82014-02-18 21:41:37 +02005550 struct smp_irk *irk;
Johan Hedberg1dc06092012-01-15 21:01:23 +02005551 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03005552
Andre Guedes12602d02013-04-30 15:29:40 -03005553 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005554 return;
Andre Guedes12602d02013-04-30 15:29:40 -03005555
Johan Hedberg1dc06092012-01-15 21:01:23 +02005556 /* Leave 5 bytes for a potential CoD field */
5557 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005558 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03005559
Johan Hedberg1dc06092012-01-15 21:01:23 +02005560 memset(buf, 0, sizeof(buf));
5561
Johan Hedberg5cedbb82014-02-18 21:41:37 +02005562 irk = hci_get_irk(hdev, bdaddr, addr_type);
5563 if (irk) {
5564 bacpy(&ev->addr.bdaddr, &irk->bdaddr);
5565 ev->addr.type = link_to_bdaddr(link_type, irk->addr_type);
5566 } else {
5567 bacpy(&ev->addr.bdaddr, bdaddr);
5568 ev->addr.type = link_to_bdaddr(link_type, addr_type);
5569 }
5570
Johan Hedberge319d2e2012-01-15 19:51:59 +02005571 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02005572 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305573 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02005574 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305575 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03005576
Johan Hedberg1dc06092012-01-15 21:01:23 +02005577 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02005578 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03005579
Johan Hedberg1dc06092012-01-15 21:01:23 +02005580 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
5581 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005582 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005583
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005584 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005585 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03005586
Marcel Holtmann901801b2013-10-06 23:55:51 -07005587 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03005588}
Johan Hedberga88a9652011-03-30 13:18:12 +03005589
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005590void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5591 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03005592{
Johan Hedbergb644ba32012-01-17 21:48:47 +02005593 struct mgmt_ev_device_found *ev;
5594 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
5595 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03005596
Johan Hedbergb644ba32012-01-17 21:48:47 +02005597 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03005598
Johan Hedbergb644ba32012-01-17 21:48:47 +02005599 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03005600
Johan Hedbergb644ba32012-01-17 21:48:47 +02005601 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005602 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005603 ev->rssi = rssi;
5604
5605 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005606 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005607
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005608 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005609
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005610 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03005611}
Johan Hedberg314b2382011-04-27 10:29:57 -04005612
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005613void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04005614{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005615 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02005616 struct pending_cmd *cmd;
5617
Andre Guedes343fb142011-11-22 17:14:19 -03005618 BT_DBG("%s discovering %u", hdev->name, discovering);
5619
Johan Hedberg164a6e72011-11-01 17:06:44 +02005620 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005621 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005622 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005623 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005624
5625 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02005626 u8 type = hdev->discovery.type;
5627
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005628 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
5629 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02005630 mgmt_pending_remove(cmd);
5631 }
5632
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005633 memset(&ev, 0, sizeof(ev));
5634 ev.type = hdev->discovery.type;
5635 ev.discovering = discovering;
5636
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005637 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04005638}
Antti Julku5e762442011-08-25 16:48:02 +03005639
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005640int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005641{
5642 struct pending_cmd *cmd;
5643 struct mgmt_ev_device_blocked ev;
5644
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005645 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005646
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005647 bacpy(&ev.addr.bdaddr, bdaddr);
5648 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005649
Johan Hedberg744cf192011-11-08 20:40:14 +02005650 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005651 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005652}
5653
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005654int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005655{
5656 struct pending_cmd *cmd;
5657 struct mgmt_ev_device_unblocked ev;
5658
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005659 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005660
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005661 bacpy(&ev.addr.bdaddr, bdaddr);
5662 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005663
Johan Hedberg744cf192011-11-08 20:40:14 +02005664 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005665 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005666}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005667
5668static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5669{
5670 BT_DBG("%s status %u", hdev->name, status);
5671
5672 /* Clear the advertising mgmt setting if we failed to re-enable it */
5673 if (status) {
5674 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005675 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005676 }
5677}
5678
5679void mgmt_reenable_advertising(struct hci_dev *hdev)
5680{
5681 struct hci_request req;
5682
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005683 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005684 return;
5685
5686 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5687 return;
5688
5689 hci_req_init(&req, hdev);
5690 enable_advertising(&req);
5691
5692 /* If this fails we have no option but to let user space know
5693 * that we've disabled advertising.
5694 */
5695 if (hci_req_run(&req, adv_enable_complete) < 0) {
5696 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005697 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005698 }
5699}