blob: 25b8b278debd1a02ce89a56b3f5bdef3da2a02c5 [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 Hedberg199a2fb2014-02-22 19:06:33 +0200820static u8 get_adv_type(struct hci_dev *hdev)
821{
822 struct pending_cmd *cmd;
823 bool connectable;
824
825 /* If there's a pending mgmt command the flag will not yet have
826 * it's final value, so check for this first.
827 */
828 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
829 if (cmd) {
830 struct mgmt_mode *cp = cmd->param;
831 connectable = !!cp->val;
832 } else {
833 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
834 }
835
836 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
837}
838
839static void enable_advertising(struct hci_request *req)
840{
841 struct hci_dev *hdev = req->hdev;
842 struct hci_cp_le_set_adv_param cp;
Johan Hedberg8f2a0602014-02-23 19:42:23 +0200843 u8 own_addr_type, enable = 0x01;
Marcel Holtmann41c90c12014-02-23 20:25:55 -0800844 bool require_privacy;
Johan Hedberg199a2fb2014-02-22 19:06:33 +0200845
Marcel Holtmann41c90c12014-02-23 20:25:55 -0800846 require_privacy = !test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg8f2a0602014-02-23 19:42:23 +0200847
Marcel Holtmann41c90c12014-02-23 20:25:55 -0800848 if (hci_update_random_address(req, require_privacy, &own_addr_type) < 0)
Johan Hedberg8f2a0602014-02-23 19:42:23 +0200849 return;
850
Marcel Holtmann41c90c12014-02-23 20:25:55 -0800851 memset(&cp, 0, sizeof(cp));
Johan Hedberg199a2fb2014-02-22 19:06:33 +0200852 cp.min_interval = __constant_cpu_to_le16(0x0800);
853 cp.max_interval = __constant_cpu_to_le16(0x0800);
854 cp.type = get_adv_type(hdev);
Johan Hedberg8f2a0602014-02-23 19:42:23 +0200855 cp.own_address_type = own_addr_type;
Johan Hedberg199a2fb2014-02-22 19:06:33 +0200856 cp.channel_map = hdev->le_adv_channel_map;
857
858 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
859
860 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
861}
862
863static void disable_advertising(struct hci_request *req)
864{
865 u8 enable = 0x00;
866
867 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
868}
869
Johan Hedberg7d785252011-12-15 00:47:39 +0200870static void service_cache_off(struct work_struct *work)
871{
872 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300873 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500874 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200875
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200876 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200877 return;
878
Johan Hedberg890ea892013-03-15 17:06:52 -0500879 hci_req_init(&req, hdev);
880
Johan Hedberg7d785252011-12-15 00:47:39 +0200881 hci_dev_lock(hdev);
882
Johan Hedberg890ea892013-03-15 17:06:52 -0500883 update_eir(&req);
884 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200885
886 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500887
888 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200889}
890
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200891static void rpa_expired(struct work_struct *work)
892{
893 struct hci_dev *hdev = container_of(work, struct hci_dev,
894 rpa_expired.work);
895 struct hci_request req;
896
897 BT_DBG("");
898
899 set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
900
901 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags) ||
902 hci_conn_num(hdev, LE_LINK) > 0)
903 return;
904
905 /* The generation of a new RPA and programming it into the
906 * controller happens in the enable_advertising() function.
907 */
908
909 hci_req_init(&req, hdev);
910
911 disable_advertising(&req);
912 enable_advertising(&req);
913
914 hci_req_run(&req, NULL);
915}
916
Johan Hedberg6a919082012-02-28 06:17:26 +0200917static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200918{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200919 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200920 return;
921
Johan Hedberg4f87da82012-03-02 19:55:56 +0200922 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedbergd6bfd592014-02-23 19:42:20 +0200923 INIT_DELAYED_WORK(&hdev->rpa_expired, rpa_expired);
Johan Hedberg7d785252011-12-15 00:47:39 +0200924
Johan Hedberg4f87da82012-03-02 19:55:56 +0200925 /* Non-mgmt controlled devices get this bit set
926 * implicitly so that pairing works for them, however
927 * for mgmt we require user-space to explicitly enable
928 * it
929 */
930 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200931}
932
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200933static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300934 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200935{
936 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200937
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200938 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200939
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300940 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200941
Johan Hedberg03811012010-12-08 00:21:06 +0200942 memset(&rp, 0, sizeof(rp));
943
Johan Hedberg03811012010-12-08 00:21:06 +0200944 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200945
946 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200947 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200948
949 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
950 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
951
952 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200953
954 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200955 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200956
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300957 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200958
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200959 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300960 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200961}
962
963static void mgmt_pending_free(struct pending_cmd *cmd)
964{
965 sock_put(cmd->sk);
966 kfree(cmd->param);
967 kfree(cmd);
968}
969
970static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300971 struct hci_dev *hdev, void *data,
972 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200973{
974 struct pending_cmd *cmd;
975
Andre Guedes12b94562012-06-07 19:05:45 -0300976 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200977 if (!cmd)
978 return NULL;
979
980 cmd->opcode = opcode;
981 cmd->index = hdev->id;
982
Andre Guedes12b94562012-06-07 19:05:45 -0300983 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200984 if (!cmd->param) {
985 kfree(cmd);
986 return NULL;
987 }
988
989 if (data)
990 memcpy(cmd->param, data, len);
991
992 cmd->sk = sk;
993 sock_hold(sk);
994
995 list_add(&cmd->list, &hdev->mgmt_pending);
996
997 return cmd;
998}
999
1000static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001001 void (*cb)(struct pending_cmd *cmd,
1002 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001003 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02001004{
Andre Guedesa3d09352013-02-01 11:21:30 -03001005 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +02001006
Andre Guedesa3d09352013-02-01 11:21:30 -03001007 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +02001008 if (opcode > 0 && cmd->opcode != opcode)
1009 continue;
1010
1011 cb(cmd, data);
1012 }
1013}
1014
Johan Hedberg03811012010-12-08 00:21:06 +02001015static void mgmt_pending_remove(struct pending_cmd *cmd)
1016{
1017 list_del(&cmd->list);
1018 mgmt_pending_free(cmd);
1019}
1020
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001021static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +02001022{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001023 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +02001024
Johan Hedbergaee9b212012-02-18 15:07:59 +02001025 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001026 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +02001027}
1028
Johan Hedberg8b064a32014-02-24 14:52:22 +02001029static void clean_up_hci_complete(struct hci_dev *hdev, u8 status)
1030{
1031 BT_DBG("%s status 0x%02x", hdev->name, status);
1032
1033 if (hci_conn_count(hdev) == 0)
1034 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1035}
1036
1037static int clean_up_hci_state(struct hci_dev *hdev)
1038{
1039 struct hci_request req;
1040 struct hci_conn *conn;
1041
1042 hci_req_init(&req, hdev);
1043
1044 if (test_bit(HCI_ISCAN, &hdev->flags) ||
1045 test_bit(HCI_PSCAN, &hdev->flags)) {
1046 u8 scan = 0x00;
1047 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1048 }
1049
1050 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1051 disable_advertising(&req);
1052
1053 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
1054 struct hci_cp_le_set_scan_enable cp;
1055
1056 memset(&cp, 0, sizeof(cp));
1057 cp.enable = LE_SCAN_DISABLE;
1058 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
1059 }
1060
1061 list_for_each_entry(conn, &hdev->conn_hash.list, list) {
1062 struct hci_cp_disconnect dc;
1063
1064 dc.handle = cpu_to_le16(conn->handle);
1065 dc.reason = 0x15; /* Terminated due to Power Off */
1066 hci_req_add(&req, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1067 }
1068
1069 return hci_req_run(&req, clean_up_hci_complete);
1070}
1071
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001072static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001073 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001074{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001075 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001076 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001077 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001078
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001079 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001080
Johan Hedberga7e80f22013-01-09 16:05:19 +02001081 if (cp->val != 0x00 && cp->val != 0x01)
1082 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1083 MGMT_STATUS_INVALID_PARAMS);
1084
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001085 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001086
Johan Hedberg87b95ba2013-09-25 13:26:06 +03001087 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
1088 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
1089 MGMT_STATUS_BUSY);
1090 goto failed;
1091 }
1092
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001093 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
1094 cancel_delayed_work(&hdev->power_off);
1095
1096 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +02001097 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
1098 data, len);
1099 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +01001100 goto failed;
1101 }
1102 }
1103
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001104 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001105 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001106 goto failed;
1107 }
1108
Johan Hedberg03811012010-12-08 00:21:06 +02001109 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
1110 if (!cmd) {
1111 err = -ENOMEM;
1112 goto failed;
1113 }
1114
Johan Hedberg8b064a32014-02-24 14:52:22 +02001115 if (cp->val) {
Johan Hedberg19202572013-01-14 22:33:51 +02001116 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg8b064a32014-02-24 14:52:22 +02001117 err = 0;
1118 } else {
1119 /* Disconnect connections, stop scans, etc */
1120 err = clean_up_hci_state(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001121
Johan Hedberg8b064a32014-02-24 14:52:22 +02001122 /* ENODATA means there were no HCI commands queued */
1123 if (err == -ENODATA) {
1124 queue_work(hdev->req_workqueue, &hdev->power_off.work);
1125 err = 0;
1126 }
1127 }
Johan Hedberg03811012010-12-08 00:21:06 +02001128
1129failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001130 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001131 return err;
1132}
1133
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001134static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
1135 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001136{
1137 struct sk_buff *skb;
1138 struct mgmt_hdr *hdr;
1139
Andre Guedes790eff42012-06-07 19:05:46 -03001140 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001141 if (!skb)
1142 return -ENOMEM;
1143
1144 hdr = (void *) skb_put(skb, sizeof(*hdr));
1145 hdr->opcode = cpu_to_le16(event);
1146 if (hdev)
1147 hdr->index = cpu_to_le16(hdev->id);
1148 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05301149 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001150 hdr->len = cpu_to_le16(data_len);
1151
1152 if (data)
1153 memcpy(skb_put(skb, data_len), data, data_len);
1154
Marcel Holtmann97e0bde2012-02-22 13:49:28 +01001155 /* Time stamp */
1156 __net_timestamp(skb);
1157
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001158 hci_send_to_control(skb, skip_sk);
1159 kfree_skb(skb);
1160
1161 return 0;
1162}
1163
1164static int new_settings(struct hci_dev *hdev, struct sock *skip)
1165{
1166 __le32 ev;
1167
1168 ev = cpu_to_le32(get_current_settings(hdev));
1169
1170 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1171}
1172
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001173struct cmd_lookup {
1174 struct sock *sk;
1175 struct hci_dev *hdev;
1176 u8 mgmt_status;
1177};
1178
1179static void settings_rsp(struct pending_cmd *cmd, void *data)
1180{
1181 struct cmd_lookup *match = data;
1182
1183 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1184
1185 list_del(&cmd->list);
1186
1187 if (match->sk == NULL) {
1188 match->sk = cmd->sk;
1189 sock_hold(match->sk);
1190 }
1191
1192 mgmt_pending_free(cmd);
1193}
1194
1195static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1196{
1197 u8 *status = data;
1198
1199 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1200 mgmt_pending_remove(cmd);
1201}
1202
Johan Hedberge6fe7982013-10-02 15:45:22 +03001203static u8 mgmt_bredr_support(struct hci_dev *hdev)
1204{
1205 if (!lmp_bredr_capable(hdev))
1206 return MGMT_STATUS_NOT_SUPPORTED;
1207 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1208 return MGMT_STATUS_REJECTED;
1209 else
1210 return MGMT_STATUS_SUCCESS;
1211}
1212
1213static u8 mgmt_le_support(struct hci_dev *hdev)
1214{
1215 if (!lmp_le_capable(hdev))
1216 return MGMT_STATUS_NOT_SUPPORTED;
1217 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1218 return MGMT_STATUS_REJECTED;
1219 else
1220 return MGMT_STATUS_SUCCESS;
1221}
1222
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001223static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1224{
1225 struct pending_cmd *cmd;
1226 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001227 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001228 bool changed;
1229
1230 BT_DBG("status 0x%02x", status);
1231
1232 hci_dev_lock(hdev);
1233
1234 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1235 if (!cmd)
1236 goto unlock;
1237
1238 if (status) {
1239 u8 mgmt_err = mgmt_status(status);
1240 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001241 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001242 goto remove_cmd;
1243 }
1244
1245 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001246 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001247 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1248 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001249
1250 if (hdev->discov_timeout > 0) {
1251 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1252 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1253 to);
1254 }
1255 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001256 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1257 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001258 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001259
1260 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1261
1262 if (changed)
1263 new_settings(hdev, cmd->sk);
1264
Marcel Holtmann970ba522013-10-15 06:33:57 -07001265 /* When the discoverable mode gets changed, make sure
1266 * that class of device has the limited discoverable
1267 * bit correctly set.
1268 */
1269 hci_req_init(&req, hdev);
1270 update_class(&req);
1271 hci_req_run(&req, NULL);
1272
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001273remove_cmd:
1274 mgmt_pending_remove(cmd);
1275
1276unlock:
1277 hci_dev_unlock(hdev);
1278}
1279
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001280static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001281 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001282{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001283 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001284 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001285 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001286 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001287 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001288 int err;
1289
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001290 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001291
Johan Hedberg9a43e252013-10-20 19:00:07 +03001292 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1293 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001294 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberg9a43e252013-10-20 19:00:07 +03001295 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001296
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001297 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga7e80f22013-01-09 16:05:19 +02001298 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1299 MGMT_STATUS_INVALID_PARAMS);
1300
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001301 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001302
1303 /* Disabling discoverable requires that no timeout is set,
1304 * and enabling limited discoverable requires a timeout.
1305 */
1306 if ((cp->val == 0x00 && timeout > 0) ||
1307 (cp->val == 0x02 && timeout == 0))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001308 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001309 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001310
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001311 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001312
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001313 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001314 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001315 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001316 goto failed;
1317 }
1318
1319 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001320 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001321 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001322 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001323 goto failed;
1324 }
1325
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001326 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001327 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001328 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001329 goto failed;
1330 }
1331
1332 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001333 bool changed = false;
1334
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001335 /* Setting limited discoverable when powered off is
1336 * not a valid operation since it requires a timeout
1337 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1338 */
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001339 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1340 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1341 changed = true;
1342 }
1343
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001344 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001345 if (err < 0)
1346 goto failed;
1347
1348 if (changed)
1349 err = new_settings(hdev, sk);
1350
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001351 goto failed;
1352 }
1353
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001354 /* If the current mode is the same, then just update the timeout
1355 * value with the new value. And if only the timeout gets updated,
1356 * then no need for any HCI transactions.
1357 */
1358 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) &&
1359 (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE,
1360 &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001361 cancel_delayed_work(&hdev->discov_off);
1362 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001363
Marcel Holtmann36261542013-10-15 08:28:51 -07001364 if (cp->val && hdev->discov_timeout > 0) {
1365 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001366 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001367 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001368 }
1369
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001370 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001371 goto failed;
1372 }
1373
1374 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1375 if (!cmd) {
1376 err = -ENOMEM;
1377 goto failed;
1378 }
1379
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001380 /* Cancel any potential discoverable timeout that might be
1381 * still active and store new timeout value. The arming of
1382 * the timeout happens in the complete handler.
1383 */
1384 cancel_delayed_work(&hdev->discov_off);
1385 hdev->discov_timeout = timeout;
1386
Johan Hedbergb456f872013-10-19 23:38:22 +03001387 /* Limited discoverable mode */
1388 if (cp->val == 0x02)
1389 set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1390 else
1391 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1392
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001393 hci_req_init(&req, hdev);
1394
Johan Hedberg9a43e252013-10-20 19:00:07 +03001395 /* The procedure for LE-only controllers is much simpler - just
1396 * update the advertising data.
1397 */
1398 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1399 goto update_ad;
1400
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001401 scan = SCAN_PAGE;
1402
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001403 if (cp->val) {
1404 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001405
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001406 if (cp->val == 0x02) {
1407 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001408 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001409 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1410 hci_cp.iac_lap[1] = 0x8b;
1411 hci_cp.iac_lap[2] = 0x9e;
1412 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1413 hci_cp.iac_lap[4] = 0x8b;
1414 hci_cp.iac_lap[5] = 0x9e;
1415 } else {
1416 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001417 hci_cp.num_iac = 1;
1418 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1419 hci_cp.iac_lap[1] = 0x8b;
1420 hci_cp.iac_lap[2] = 0x9e;
1421 }
1422
1423 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1424 (hci_cp.num_iac * 3) + 1, &hci_cp);
1425
1426 scan |= SCAN_INQUIRY;
1427 } else {
1428 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1429 }
1430
1431 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001432
Johan Hedberg9a43e252013-10-20 19:00:07 +03001433update_ad:
1434 update_adv_data(&req);
1435
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001436 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001437 if (err < 0)
1438 mgmt_pending_remove(cmd);
1439
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001440failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001441 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001442 return err;
1443}
1444
Johan Hedberg406d7802013-03-15 17:07:09 -05001445static void write_fast_connectable(struct hci_request *req, bool enable)
1446{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001447 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001448 struct hci_cp_write_page_scan_activity acp;
1449 u8 type;
1450
Johan Hedberg547003b2013-10-21 16:51:53 +03001451 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1452 return;
1453
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001454 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1455 return;
1456
Johan Hedberg406d7802013-03-15 17:07:09 -05001457 if (enable) {
1458 type = PAGE_SCAN_TYPE_INTERLACED;
1459
1460 /* 160 msec page scan interval */
1461 acp.interval = __constant_cpu_to_le16(0x0100);
1462 } else {
1463 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1464
1465 /* default 1.28 sec page scan */
1466 acp.interval = __constant_cpu_to_le16(0x0800);
1467 }
1468
1469 acp.window = __constant_cpu_to_le16(0x0012);
1470
Johan Hedbergbd98b992013-03-15 17:07:13 -05001471 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1472 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1473 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1474 sizeof(acp), &acp);
1475
1476 if (hdev->page_scan_type != type)
1477 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001478}
1479
Johan Hedberg2b76f452013-03-15 17:07:04 -05001480static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1481{
1482 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001483 struct mgmt_mode *cp;
1484 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001485
1486 BT_DBG("status 0x%02x", status);
1487
1488 hci_dev_lock(hdev);
1489
1490 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1491 if (!cmd)
1492 goto unlock;
1493
Johan Hedberg37438c12013-10-14 16:20:05 +03001494 if (status) {
1495 u8 mgmt_err = mgmt_status(status);
1496 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1497 goto remove_cmd;
1498 }
1499
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001500 cp = cmd->param;
1501 if (cp->val)
1502 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1503 else
1504 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1505
Johan Hedberg2b76f452013-03-15 17:07:04 -05001506 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1507
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001508 if (changed)
1509 new_settings(hdev, cmd->sk);
1510
Johan Hedberg37438c12013-10-14 16:20:05 +03001511remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001512 mgmt_pending_remove(cmd);
1513
1514unlock:
1515 hci_dev_unlock(hdev);
1516}
1517
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001518static int set_connectable_update_settings(struct hci_dev *hdev,
1519 struct sock *sk, u8 val)
1520{
1521 bool changed = false;
1522 int err;
1523
1524 if (!!val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1525 changed = true;
1526
1527 if (val) {
1528 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1529 } else {
1530 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1531 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1532 }
1533
1534 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1535 if (err < 0)
1536 return err;
1537
1538 if (changed)
1539 return new_settings(hdev, sk);
1540
1541 return 0;
1542}
1543
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001544static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001545 u16 len)
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001546{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001547 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001548 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001549 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001550 u8 scan;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001551 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001552
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001553 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001554
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001555 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1556 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001557 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001558 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001559
Johan Hedberga7e80f22013-01-09 16:05:19 +02001560 if (cp->val != 0x00 && cp->val != 0x01)
1561 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1562 MGMT_STATUS_INVALID_PARAMS);
1563
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001564 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001565
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001566 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001567 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001568 goto failed;
1569 }
1570
1571 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001572 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001573 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001574 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001575 goto failed;
1576 }
1577
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001578 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1579 if (!cmd) {
1580 err = -ENOMEM;
1581 goto failed;
1582 }
1583
Johan Hedberg2b76f452013-03-15 17:07:04 -05001584 hci_req_init(&req, hdev);
1585
Johan Hedberg9a43e252013-10-20 19:00:07 +03001586 /* If BR/EDR is not enabled and we disable advertising as a
1587 * by-product of disabling connectable, we need to update the
1588 * advertising flags.
1589 */
1590 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
1591 if (!cp->val) {
1592 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1593 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1594 }
1595 update_adv_data(&req);
1596 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001597 if (cp->val) {
1598 scan = SCAN_PAGE;
1599 } else {
1600 scan = 0;
1601
1602 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001603 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001604 cancel_delayed_work(&hdev->discov_off);
1605 }
1606
1607 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1608 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001609
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001610 /* If we're going from non-connectable to connectable or
1611 * vice-versa when fast connectable is enabled ensure that fast
1612 * connectable gets disabled. write_fast_connectable won't do
1613 * anything if the page scan parameters are already what they
1614 * should be.
1615 */
1616 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001617 write_fast_connectable(&req, false);
1618
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001619 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1620 hci_conn_num(hdev, LE_LINK) == 0) {
1621 disable_advertising(&req);
1622 enable_advertising(&req);
1623 }
1624
Johan Hedberg2b76f452013-03-15 17:07:04 -05001625 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001626 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001627 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001628 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03001629 err = set_connectable_update_settings(hdev, sk,
1630 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03001631 goto failed;
1632 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001633
1634failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001635 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001636 return err;
1637}
1638
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001639static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001640 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001641{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001642 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001643 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001644 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001645
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001646 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001647
Johan Hedberga7e80f22013-01-09 16:05:19 +02001648 if (cp->val != 0x00 && cp->val != 0x01)
1649 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1650 MGMT_STATUS_INVALID_PARAMS);
1651
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001652 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001653
1654 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001655 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001656 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001657 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001658
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001659 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001660 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001661 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001662
Marcel Holtmann55594352013-10-06 16:11:57 -07001663 if (changed)
1664 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001665
Marcel Holtmann55594352013-10-06 16:11:57 -07001666unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001667 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001668 return err;
1669}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001670
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001671static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1672 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001673{
1674 struct mgmt_mode *cp = data;
1675 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001676 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001677 int err;
1678
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001679 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001680
Johan Hedberge6fe7982013-10-02 15:45:22 +03001681 status = mgmt_bredr_support(hdev);
1682 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001683 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001684 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001685
Johan Hedberga7e80f22013-01-09 16:05:19 +02001686 if (cp->val != 0x00 && cp->val != 0x01)
1687 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1688 MGMT_STATUS_INVALID_PARAMS);
1689
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001690 hci_dev_lock(hdev);
1691
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001692 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001693 bool changed = false;
1694
1695 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001696 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001697 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1698 changed = true;
1699 }
1700
1701 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1702 if (err < 0)
1703 goto failed;
1704
1705 if (changed)
1706 err = new_settings(hdev, sk);
1707
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001708 goto failed;
1709 }
1710
1711 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001712 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001713 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001714 goto failed;
1715 }
1716
1717 val = !!cp->val;
1718
1719 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1720 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1721 goto failed;
1722 }
1723
1724 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1725 if (!cmd) {
1726 err = -ENOMEM;
1727 goto failed;
1728 }
1729
1730 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1731 if (err < 0) {
1732 mgmt_pending_remove(cmd);
1733 goto failed;
1734 }
1735
1736failed:
1737 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001738 return err;
1739}
1740
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001741static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001742{
1743 struct mgmt_mode *cp = data;
1744 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001745 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001746 int err;
1747
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001748 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001749
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001750 status = mgmt_bredr_support(hdev);
1751 if (status)
1752 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1753
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001754 if (!lmp_ssp_capable(hdev))
1755 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1756 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001757
Johan Hedberga7e80f22013-01-09 16:05:19 +02001758 if (cp->val != 0x00 && cp->val != 0x01)
1759 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1760 MGMT_STATUS_INVALID_PARAMS);
1761
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001762 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001763
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001764 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001765 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001766
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001767 if (cp->val) {
1768 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1769 &hdev->dev_flags);
1770 } else {
1771 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1772 &hdev->dev_flags);
1773 if (!changed)
1774 changed = test_and_clear_bit(HCI_HS_ENABLED,
1775 &hdev->dev_flags);
1776 else
1777 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001778 }
1779
1780 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1781 if (err < 0)
1782 goto failed;
1783
1784 if (changed)
1785 err = new_settings(hdev, sk);
1786
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001787 goto failed;
1788 }
1789
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001790 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1791 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001792 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1793 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001794 goto failed;
1795 }
1796
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001797 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001798 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1799 goto failed;
1800 }
1801
1802 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1803 if (!cmd) {
1804 err = -ENOMEM;
1805 goto failed;
1806 }
1807
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001808 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001809 if (err < 0) {
1810 mgmt_pending_remove(cmd);
1811 goto failed;
1812 }
1813
1814failed:
1815 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001816 return err;
1817}
1818
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001819static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001820{
1821 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001822 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001823 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001824 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001825
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001826 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001827
Johan Hedberge6fe7982013-10-02 15:45:22 +03001828 status = mgmt_bredr_support(hdev);
1829 if (status)
1830 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001831
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001832 if (!lmp_ssp_capable(hdev))
1833 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1834 MGMT_STATUS_NOT_SUPPORTED);
1835
1836 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1837 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1838 MGMT_STATUS_REJECTED);
1839
Johan Hedberga7e80f22013-01-09 16:05:19 +02001840 if (cp->val != 0x00 && cp->val != 0x01)
1841 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1842 MGMT_STATUS_INVALID_PARAMS);
1843
Marcel Holtmannee392692013-10-01 22:59:23 -07001844 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001845
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001846 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001847 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001848 } else {
1849 if (hdev_is_powered(hdev)) {
1850 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1851 MGMT_STATUS_REJECTED);
1852 goto unlock;
1853 }
1854
Marcel Holtmannee392692013-10-01 22:59:23 -07001855 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001856 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001857
1858 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1859 if (err < 0)
1860 goto unlock;
1861
1862 if (changed)
1863 err = new_settings(hdev, sk);
1864
1865unlock:
1866 hci_dev_unlock(hdev);
1867 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001868}
1869
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001870static void le_enable_complete(struct hci_dev *hdev, u8 status)
1871{
1872 struct cmd_lookup match = { NULL, hdev };
1873
1874 if (status) {
1875 u8 mgmt_err = mgmt_status(status);
1876
1877 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1878 &mgmt_err);
1879 return;
1880 }
1881
1882 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1883
1884 new_settings(hdev, match.sk);
1885
1886 if (match.sk)
1887 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001888
1889 /* Make sure the controller has a good default for
1890 * advertising data. Restrict the update to when LE
1891 * has actually been enabled. During power on, the
1892 * update in powered_update_hci will take care of it.
1893 */
1894 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1895 struct hci_request req;
1896
1897 hci_dev_lock(hdev);
1898
1899 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001900 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07001901 update_scan_rsp_data(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001902 hci_req_run(&req, NULL);
1903
1904 hci_dev_unlock(hdev);
1905 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001906}
1907
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001908static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001909{
1910 struct mgmt_mode *cp = data;
1911 struct hci_cp_write_le_host_supported hci_cp;
1912 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001913 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001914 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001915 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001916
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001917 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001918
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001919 if (!lmp_le_capable(hdev))
1920 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1921 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001922
Johan Hedberga7e80f22013-01-09 16:05:19 +02001923 if (cp->val != 0x00 && cp->val != 0x01)
1924 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1925 MGMT_STATUS_INVALID_PARAMS);
1926
Johan Hedbergc73eee92013-04-19 18:35:21 +03001927 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001928 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001929 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1930 MGMT_STATUS_REJECTED);
1931
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001932 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001933
1934 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001935 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001936
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001937 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001938 bool changed = false;
1939
1940 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1941 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1942 changed = true;
1943 }
1944
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001945 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1946 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001947 changed = true;
1948 }
1949
Johan Hedberg06199cf2012-02-22 16:37:11 +02001950 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1951 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001952 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001953
1954 if (changed)
1955 err = new_settings(hdev, sk);
1956
Johan Hedberg1de028c2012-02-29 19:55:35 -08001957 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001958 }
1959
Johan Hedberg4375f102013-09-25 13:26:10 +03001960 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1961 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001962 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001963 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001964 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001965 }
1966
1967 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1968 if (!cmd) {
1969 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001970 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001971 }
1972
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001973 hci_req_init(&req, hdev);
1974
Johan Hedberg06199cf2012-02-22 16:37:11 +02001975 memset(&hci_cp, 0, sizeof(hci_cp));
1976
1977 if (val) {
1978 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001979 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001980 } else {
1981 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1982 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001983 }
1984
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001985 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1986 &hci_cp);
1987
1988 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301989 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001990 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001991
Johan Hedberg1de028c2012-02-29 19:55:35 -08001992unlock:
1993 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001994 return err;
1995}
1996
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001997/* This is a helper function to test for pending mgmt commands that can
1998 * cause CoD or EIR HCI commands. We can only allow one such pending
1999 * mgmt command at a time since otherwise we cannot easily track what
2000 * the current values are, will be, and based on that calculate if a new
2001 * HCI command needs to be sent and if yes with what value.
2002 */
2003static bool pending_eir_or_class(struct hci_dev *hdev)
2004{
2005 struct pending_cmd *cmd;
2006
2007 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
2008 switch (cmd->opcode) {
2009 case MGMT_OP_ADD_UUID:
2010 case MGMT_OP_REMOVE_UUID:
2011 case MGMT_OP_SET_DEV_CLASS:
2012 case MGMT_OP_SET_POWERED:
2013 return true;
2014 }
2015 }
2016
2017 return false;
2018}
2019
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002020static const u8 bluetooth_base_uuid[] = {
2021 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
2022 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2023};
2024
2025static u8 get_uuid_size(const u8 *uuid)
2026{
2027 u32 val;
2028
2029 if (memcmp(uuid, bluetooth_base_uuid, 12))
2030 return 128;
2031
2032 val = get_unaligned_le32(&uuid[12]);
2033 if (val > 0xffff)
2034 return 32;
2035
2036 return 16;
2037}
2038
Johan Hedberg92da6092013-03-15 17:06:55 -05002039static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
2040{
2041 struct pending_cmd *cmd;
2042
2043 hci_dev_lock(hdev);
2044
2045 cmd = mgmt_pending_find(mgmt_op, hdev);
2046 if (!cmd)
2047 goto unlock;
2048
2049 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
2050 hdev->dev_class, 3);
2051
2052 mgmt_pending_remove(cmd);
2053
2054unlock:
2055 hci_dev_unlock(hdev);
2056}
2057
2058static void add_uuid_complete(struct hci_dev *hdev, u8 status)
2059{
2060 BT_DBG("status 0x%02x", status);
2061
2062 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
2063}
2064
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002065static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002066{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002067 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002068 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002069 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002070 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002071 int err;
2072
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002073 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002074
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002075 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002076
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002077 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002078 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002079 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002080 goto failed;
2081 }
2082
Andre Guedes92c4c202012-06-07 19:05:44 -03002083 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002084 if (!uuid) {
2085 err = -ENOMEM;
2086 goto failed;
2087 }
2088
2089 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002090 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002091 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002092
Johan Hedbergde66aa62013-01-27 00:31:27 +02002093 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002094
Johan Hedberg890ea892013-03-15 17:06:52 -05002095 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002096
Johan Hedberg890ea892013-03-15 17:06:52 -05002097 update_class(&req);
2098 update_eir(&req);
2099
Johan Hedberg92da6092013-03-15 17:06:55 -05002100 err = hci_req_run(&req, add_uuid_complete);
2101 if (err < 0) {
2102 if (err != -ENODATA)
2103 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002104
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002105 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002106 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002107 goto failed;
2108 }
2109
2110 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002111 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002112 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002113 goto failed;
2114 }
2115
2116 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002117
2118failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002119 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002120 return err;
2121}
2122
Johan Hedberg24b78d02012-02-23 23:24:30 +02002123static bool enable_service_cache(struct hci_dev *hdev)
2124{
2125 if (!hdev_is_powered(hdev))
2126 return false;
2127
2128 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002129 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2130 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002131 return true;
2132 }
2133
2134 return false;
2135}
2136
Johan Hedberg92da6092013-03-15 17:06:55 -05002137static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
2138{
2139 BT_DBG("status 0x%02x", status);
2140
2141 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2142}
2143
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002144static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002145 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002146{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002147 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002148 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002149 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002150 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 -05002151 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002152 int err, found;
2153
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002154 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002155
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002156 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002157
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002158 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002159 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002160 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002161 goto unlock;
2162 }
2163
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002164 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002165 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002166
Johan Hedberg24b78d02012-02-23 23:24:30 +02002167 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002168 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002169 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002170 goto unlock;
2171 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002172
Johan Hedberg9246a862012-02-23 21:33:16 +02002173 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002174 }
2175
2176 found = 0;
2177
Johan Hedberg056341c2013-01-27 00:31:30 +02002178 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002179 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2180 continue;
2181
2182 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002183 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002184 found++;
2185 }
2186
2187 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002188 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002189 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002190 goto unlock;
2191 }
2192
Johan Hedberg9246a862012-02-23 21:33:16 +02002193update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002194 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002195
Johan Hedberg890ea892013-03-15 17:06:52 -05002196 update_class(&req);
2197 update_eir(&req);
2198
Johan Hedberg92da6092013-03-15 17:06:55 -05002199 err = hci_req_run(&req, remove_uuid_complete);
2200 if (err < 0) {
2201 if (err != -ENODATA)
2202 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002203
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002204 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002205 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002206 goto unlock;
2207 }
2208
2209 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002210 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002211 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002212 goto unlock;
2213 }
2214
2215 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002216
2217unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002218 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002219 return err;
2220}
2221
Johan Hedberg92da6092013-03-15 17:06:55 -05002222static void set_class_complete(struct hci_dev *hdev, u8 status)
2223{
2224 BT_DBG("status 0x%02x", status);
2225
2226 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2227}
2228
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002229static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002230 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002231{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002232 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002233 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002234 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002235 int err;
2236
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002237 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002238
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002239 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002240 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2241 MGMT_STATUS_NOT_SUPPORTED);
2242
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002243 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002244
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002245 if (pending_eir_or_class(hdev)) {
2246 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2247 MGMT_STATUS_BUSY);
2248 goto unlock;
2249 }
2250
2251 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2252 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2253 MGMT_STATUS_INVALID_PARAMS);
2254 goto unlock;
2255 }
2256
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002257 hdev->major_class = cp->major;
2258 hdev->minor_class = cp->minor;
2259
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002260 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002261 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002262 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002263 goto unlock;
2264 }
2265
Johan Hedberg890ea892013-03-15 17:06:52 -05002266 hci_req_init(&req, hdev);
2267
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002268 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002269 hci_dev_unlock(hdev);
2270 cancel_delayed_work_sync(&hdev->service_cache);
2271 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002272 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002273 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002274
Johan Hedberg890ea892013-03-15 17:06:52 -05002275 update_class(&req);
2276
Johan Hedberg92da6092013-03-15 17:06:55 -05002277 err = hci_req_run(&req, set_class_complete);
2278 if (err < 0) {
2279 if (err != -ENODATA)
2280 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002281
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002282 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002283 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002284 goto unlock;
2285 }
2286
2287 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002288 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002289 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002290 goto unlock;
2291 }
2292
2293 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002294
Johan Hedbergb5235a62012-02-21 14:32:24 +02002295unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002296 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002297 return err;
2298}
2299
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002300static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002301 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002302{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002303 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002304 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002305 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002306 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002307
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002308 BT_DBG("request for %s", hdev->name);
2309
2310 if (!lmp_bredr_capable(hdev))
2311 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2312 MGMT_STATUS_NOT_SUPPORTED);
2313
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002314 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002315
Johan Hedberg86742e12011-11-07 23:13:38 +02002316 expected_len = sizeof(*cp) + key_count *
2317 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002318 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002319 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002320 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002321 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002322 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002323 }
2324
Johan Hedberg4ae14302013-01-20 14:27:13 +02002325 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2326 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2327 MGMT_STATUS_INVALID_PARAMS);
2328
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002329 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002330 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002331
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002332 for (i = 0; i < key_count; i++) {
2333 struct mgmt_link_key_info *key = &cp->keys[i];
2334
Marcel Holtmann8e991132014-01-10 02:07:25 -08002335 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002336 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2337 MGMT_STATUS_INVALID_PARAMS);
2338 }
2339
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002340 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002341
2342 hci_link_keys_clear(hdev);
2343
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002344 if (cp->debug_keys)
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002345 changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002346 else
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002347 changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
2348
2349 if (changed)
2350 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002351
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002352 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002353 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002354
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002355 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002356 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002357 }
2358
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002359 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002360
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002361 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002362
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002363 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002364}
2365
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002366static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002367 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002368{
2369 struct mgmt_ev_device_unpaired ev;
2370
2371 bacpy(&ev.addr.bdaddr, bdaddr);
2372 ev.addr.type = addr_type;
2373
2374 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002375 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002376}
2377
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002378static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002379 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002380{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002381 struct mgmt_cp_unpair_device *cp = data;
2382 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002383 struct hci_cp_disconnect dc;
2384 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002385 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002386 int err;
2387
Johan Hedberga8a1d192011-11-10 15:54:38 +02002388 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002389 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2390 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002391
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002392 if (!bdaddr_type_is_valid(cp->addr.type))
2393 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2394 MGMT_STATUS_INVALID_PARAMS,
2395 &rp, sizeof(rp));
2396
Johan Hedberg118da702013-01-20 14:27:20 +02002397 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2398 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2399 MGMT_STATUS_INVALID_PARAMS,
2400 &rp, sizeof(rp));
2401
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002402 hci_dev_lock(hdev);
2403
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002404 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002405 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002406 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002407 goto unlock;
2408 }
2409
Johan Hedberge0b2b272014-02-18 17:14:31 +02002410 if (cp->addr.type == BDADDR_BREDR) {
Johan Hedberg124f6e32012-02-09 13:50:12 +02002411 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedberge0b2b272014-02-18 17:14:31 +02002412 } else {
2413 u8 addr_type;
2414
2415 if (cp->addr.type == BDADDR_LE_PUBLIC)
2416 addr_type = ADDR_LE_DEV_PUBLIC;
2417 else
2418 addr_type = ADDR_LE_DEV_RANDOM;
2419
Johan Hedberga7ec7332014-02-18 17:14:35 +02002420 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2421
Johan Hedberge0b2b272014-02-18 17:14:31 +02002422 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
2423 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002424
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002425 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002426 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002427 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002428 goto unlock;
2429 }
2430
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002431 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002432 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002433 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002434 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002435 else
2436 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002437 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002438 } else {
2439 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002440 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002441
Johan Hedberga8a1d192011-11-10 15:54:38 +02002442 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002443 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002444 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002445 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002446 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002447 }
2448
Johan Hedberg124f6e32012-02-09 13:50:12 +02002449 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002450 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002451 if (!cmd) {
2452 err = -ENOMEM;
2453 goto unlock;
2454 }
2455
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002456 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002457 dc.reason = 0x13; /* Remote User Terminated Connection */
2458 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2459 if (err < 0)
2460 mgmt_pending_remove(cmd);
2461
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002462unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002463 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002464 return err;
2465}
2466
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002467static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002468 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002469{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002470 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002471 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002472 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002473 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002474 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002475 int err;
2476
2477 BT_DBG("");
2478
Johan Hedberg06a63b12013-01-20 14:27:21 +02002479 memset(&rp, 0, sizeof(rp));
2480 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2481 rp.addr.type = cp->addr.type;
2482
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002483 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002484 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2485 MGMT_STATUS_INVALID_PARAMS,
2486 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002487
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002488 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002489
2490 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002491 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2492 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002493 goto failed;
2494 }
2495
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002496 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002497 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2498 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002499 goto failed;
2500 }
2501
Andre Guedes591f47f2012-04-24 21:02:49 -03002502 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002503 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2504 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002505 else
2506 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002507
Vishal Agarwalf9607272012-06-13 05:32:43 +05302508 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002509 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2510 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002511 goto failed;
2512 }
2513
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002514 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002515 if (!cmd) {
2516 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002517 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002518 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002519
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002520 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002521 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002522
2523 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2524 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002525 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002526
2527failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002528 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002529 return err;
2530}
2531
Andre Guedes57c14772012-04-24 21:02:50 -03002532static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002533{
2534 switch (link_type) {
2535 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002536 switch (addr_type) {
2537 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002538 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002539
Johan Hedberg48264f02011-11-09 13:58:58 +02002540 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002541 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002542 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002543 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002544
Johan Hedberg4c659c32011-11-07 23:13:39 +02002545 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002546 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002547 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002548 }
2549}
2550
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002551static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2552 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002553{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002554 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002555 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002556 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002557 int err;
2558 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002559
2560 BT_DBG("");
2561
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002562 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002563
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002564 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002565 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002566 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002567 goto unlock;
2568 }
2569
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002570 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002571 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2572 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002573 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002574 }
2575
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002576 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002577 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002578 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002579 err = -ENOMEM;
2580 goto unlock;
2581 }
2582
Johan Hedberg2784eb42011-01-21 13:56:35 +02002583 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002584 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002585 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2586 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002587 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002588 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002589 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002590 continue;
2591 i++;
2592 }
2593
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002594 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002595
Johan Hedberg4c659c32011-11-07 23:13:39 +02002596 /* Recalculate length in case of filtered SCO connections, etc */
2597 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002598
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002599 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002600 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002601
Johan Hedberga38528f2011-01-22 06:46:43 +02002602 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002603
2604unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002605 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002606 return err;
2607}
2608
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002609static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002610 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002611{
2612 struct pending_cmd *cmd;
2613 int err;
2614
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002615 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002616 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002617 if (!cmd)
2618 return -ENOMEM;
2619
Johan Hedbergd8457692012-02-17 14:24:57 +02002620 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002621 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002622 if (err < 0)
2623 mgmt_pending_remove(cmd);
2624
2625 return err;
2626}
2627
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002628static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002629 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002630{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002631 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002632 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002633 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002634 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002635 int err;
2636
2637 BT_DBG("");
2638
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002639 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002640
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002641 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002642 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002643 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002644 goto failed;
2645 }
2646
Johan Hedbergd8457692012-02-17 14:24:57 +02002647 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002648 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002649 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002650 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002651 goto failed;
2652 }
2653
2654 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002655 struct mgmt_cp_pin_code_neg_reply ncp;
2656
2657 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002658
2659 BT_ERR("PIN code is not 16 bytes long");
2660
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002661 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002662 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002663 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002664 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002665
2666 goto failed;
2667 }
2668
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002669 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002670 if (!cmd) {
2671 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002672 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002673 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002674
Johan Hedbergd8457692012-02-17 14:24:57 +02002675 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002676 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002677 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002678
2679 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2680 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002681 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002682
2683failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002684 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002685 return err;
2686}
2687
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002688static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2689 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002690{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002691 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002692
2693 BT_DBG("");
2694
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002695 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002696
2697 hdev->io_capability = cp->io_capability;
2698
2699 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002700 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002701
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002702 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002703
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002704 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2705 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002706}
2707
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002708static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002709{
2710 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002711 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002712
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002713 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002714 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2715 continue;
2716
Johan Hedberge9a416b2011-02-19 12:05:56 -03002717 if (cmd->user_data != conn)
2718 continue;
2719
2720 return cmd;
2721 }
2722
2723 return NULL;
2724}
2725
2726static void pairing_complete(struct pending_cmd *cmd, u8 status)
2727{
2728 struct mgmt_rp_pair_device rp;
2729 struct hci_conn *conn = cmd->user_data;
2730
Johan Hedbergba4e5642011-11-11 00:07:34 +02002731 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002732 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002733
Johan Hedbergaee9b212012-02-18 15:07:59 +02002734 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002735 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002736
2737 /* So we don't get further callbacks for this connection */
2738 conn->connect_cfm_cb = NULL;
2739 conn->security_cfm_cb = NULL;
2740 conn->disconn_cfm_cb = NULL;
2741
David Herrmann76a68ba2013-04-06 20:28:37 +02002742 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002743
Johan Hedberga664b5b2011-02-19 12:06:02 -03002744 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002745}
2746
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002747void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2748{
2749 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
2750 struct pending_cmd *cmd;
2751
2752 cmd = find_pairing(conn);
2753 if (cmd)
2754 pairing_complete(cmd, status);
2755}
2756
Johan Hedberge9a416b2011-02-19 12:05:56 -03002757static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2758{
2759 struct pending_cmd *cmd;
2760
2761 BT_DBG("status %u", status);
2762
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002763 cmd = find_pairing(conn);
2764 if (!cmd)
2765 BT_DBG("Unable to find a pending command");
2766 else
Johan Hedberge2113262012-02-18 15:20:03 +02002767 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002768}
2769
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002770static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302771{
2772 struct pending_cmd *cmd;
2773
2774 BT_DBG("status %u", status);
2775
2776 if (!status)
2777 return;
2778
2779 cmd = find_pairing(conn);
2780 if (!cmd)
2781 BT_DBG("Unable to find a pending command");
2782 else
2783 pairing_complete(cmd, mgmt_status(status));
2784}
2785
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002786static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002787 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002788{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002789 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002790 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002791 struct pending_cmd *cmd;
2792 u8 sec_level, auth_type;
2793 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002794 int err;
2795
2796 BT_DBG("");
2797
Szymon Jancf950a30e2013-01-18 12:48:07 +01002798 memset(&rp, 0, sizeof(rp));
2799 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2800 rp.addr.type = cp->addr.type;
2801
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002802 if (!bdaddr_type_is_valid(cp->addr.type))
2803 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2804 MGMT_STATUS_INVALID_PARAMS,
2805 &rp, sizeof(rp));
2806
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002807 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002808
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002809 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002810 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2811 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002812 goto unlock;
2813 }
2814
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002815 sec_level = BT_SECURITY_MEDIUM;
2816 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002817 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002818 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002819 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002820
Andre Guedes591f47f2012-04-24 21:02:49 -03002821 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002822 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2823 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002824 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002825 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2826 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002827
Ville Tervo30e76272011-02-22 16:10:53 -03002828 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002829 int status;
2830
2831 if (PTR_ERR(conn) == -EBUSY)
2832 status = MGMT_STATUS_BUSY;
2833 else
2834 status = MGMT_STATUS_CONNECT_FAILED;
2835
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002836 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002837 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002838 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002839 goto unlock;
2840 }
2841
2842 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002843 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002844 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002845 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002846 goto unlock;
2847 }
2848
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002849 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002850 if (!cmd) {
2851 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002852 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002853 goto unlock;
2854 }
2855
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002856 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002857 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002858 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002859 conn->security_cfm_cb = pairing_complete_cb;
2860 conn->disconn_cfm_cb = pairing_complete_cb;
2861 } else {
2862 conn->connect_cfm_cb = le_pairing_complete_cb;
2863 conn->security_cfm_cb = le_pairing_complete_cb;
2864 conn->disconn_cfm_cb = le_pairing_complete_cb;
2865 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002866
Johan Hedberge9a416b2011-02-19 12:05:56 -03002867 conn->io_capability = cp->io_cap;
2868 cmd->user_data = conn;
2869
2870 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002871 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002872 pairing_complete(cmd, 0);
2873
2874 err = 0;
2875
2876unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002877 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002878 return err;
2879}
2880
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002881static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2882 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002883{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002884 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002885 struct pending_cmd *cmd;
2886 struct hci_conn *conn;
2887 int err;
2888
2889 BT_DBG("");
2890
Johan Hedberg28424702012-02-02 04:02:29 +02002891 hci_dev_lock(hdev);
2892
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002893 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002894 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002895 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002896 goto unlock;
2897 }
2898
Johan Hedberg28424702012-02-02 04:02:29 +02002899 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2900 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002901 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002902 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002903 goto unlock;
2904 }
2905
2906 conn = cmd->user_data;
2907
2908 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002909 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002910 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002911 goto unlock;
2912 }
2913
2914 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2915
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002916 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002917 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002918unlock:
2919 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002920 return err;
2921}
2922
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002923static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002924 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002925 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002926{
Johan Hedberga5c29682011-02-19 12:05:57 -03002927 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002928 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002929 int err;
2930
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002931 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002932
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002933 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002934 err = cmd_complete(sk, hdev->id, mgmt_op,
2935 MGMT_STATUS_NOT_POWERED, addr,
2936 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002937 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002938 }
2939
Johan Hedberg1707c602013-03-15 17:07:15 -05002940 if (addr->type == BDADDR_BREDR)
2941 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002942 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002943 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002944
Johan Hedberg272d90d2012-02-09 15:26:12 +02002945 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002946 err = cmd_complete(sk, hdev->id, mgmt_op,
2947 MGMT_STATUS_NOT_CONNECTED, addr,
2948 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002949 goto done;
2950 }
2951
Johan Hedberg1707c602013-03-15 17:07:15 -05002952 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002953 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002954 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002955
Brian Gix5fe57d92011-12-21 16:12:13 -08002956 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002957 err = cmd_complete(sk, hdev->id, mgmt_op,
2958 MGMT_STATUS_SUCCESS, addr,
2959 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002960 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002961 err = cmd_complete(sk, hdev->id, mgmt_op,
2962 MGMT_STATUS_FAILED, addr,
2963 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002964
Brian Gix47c15e22011-11-16 13:53:14 -08002965 goto done;
2966 }
2967
Johan Hedberg1707c602013-03-15 17:07:15 -05002968 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002969 if (!cmd) {
2970 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002971 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002972 }
2973
Brian Gix0df4c182011-11-16 13:53:13 -08002974 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002975 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2976 struct hci_cp_user_passkey_reply cp;
2977
Johan Hedberg1707c602013-03-15 17:07:15 -05002978 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002979 cp.passkey = passkey;
2980 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2981 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002982 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2983 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002984
Johan Hedberga664b5b2011-02-19 12:06:02 -03002985 if (err < 0)
2986 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002987
Brian Gix0df4c182011-11-16 13:53:13 -08002988done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002989 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002990 return err;
2991}
2992
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302993static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2994 void *data, u16 len)
2995{
2996 struct mgmt_cp_pin_code_neg_reply *cp = data;
2997
2998 BT_DBG("");
2999
Johan Hedberg1707c602013-03-15 17:07:15 -05003000 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05303001 MGMT_OP_PIN_CODE_NEG_REPLY,
3002 HCI_OP_PIN_CODE_NEG_REPLY, 0);
3003}
3004
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003005static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3006 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003007{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003008 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003009
3010 BT_DBG("");
3011
3012 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003013 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003014 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08003015
Johan Hedberg1707c602013-03-15 17:07:15 -05003016 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003017 MGMT_OP_USER_CONFIRM_REPLY,
3018 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003019}
3020
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003021static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003022 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08003023{
Johan Hedbergc9c26592011-12-15 00:47:41 +02003024 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08003025
3026 BT_DBG("");
3027
Johan Hedberg1707c602013-03-15 17:07:15 -05003028 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003029 MGMT_OP_USER_CONFIRM_NEG_REPLY,
3030 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08003031}
3032
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003033static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
3034 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003035{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003036 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003037
3038 BT_DBG("");
3039
Johan Hedberg1707c602013-03-15 17:07:15 -05003040 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003041 MGMT_OP_USER_PASSKEY_REPLY,
3042 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08003043}
3044
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003045static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003046 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08003047{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003048 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08003049
3050 BT_DBG("");
3051
Johan Hedberg1707c602013-03-15 17:07:15 -05003052 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003053 MGMT_OP_USER_PASSKEY_NEG_REPLY,
3054 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08003055}
3056
Johan Hedberg13928972013-03-15 17:07:00 -05003057static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003058{
Johan Hedberg13928972013-03-15 17:07:00 -05003059 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003060 struct hci_cp_write_local_name cp;
3061
Johan Hedberg13928972013-03-15 17:07:00 -05003062 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003063
Johan Hedberg890ea892013-03-15 17:06:52 -05003064 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003065}
3066
Johan Hedberg13928972013-03-15 17:07:00 -05003067static void set_name_complete(struct hci_dev *hdev, u8 status)
3068{
3069 struct mgmt_cp_set_local_name *cp;
3070 struct pending_cmd *cmd;
3071
3072 BT_DBG("status 0x%02x", status);
3073
3074 hci_dev_lock(hdev);
3075
3076 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
3077 if (!cmd)
3078 goto unlock;
3079
3080 cp = cmd->param;
3081
3082 if (status)
3083 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
3084 mgmt_status(status));
3085 else
3086 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3087 cp, sizeof(*cp));
3088
3089 mgmt_pending_remove(cmd);
3090
3091unlock:
3092 hci_dev_unlock(hdev);
3093}
3094
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003095static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003096 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003097{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003098 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003099 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003100 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003101 int err;
3102
3103 BT_DBG("");
3104
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003105 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003106
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003107 /* If the old values are the same as the new ones just return a
3108 * direct command complete event.
3109 */
3110 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3111 !memcmp(hdev->short_name, cp->short_name,
3112 sizeof(hdev->short_name))) {
3113 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3114 data, len);
3115 goto failed;
3116 }
3117
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003118 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003119
Johan Hedbergb5235a62012-02-21 14:32:24 +02003120 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003121 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003122
3123 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003124 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003125 if (err < 0)
3126 goto failed;
3127
3128 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003129 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003130
Johan Hedbergb5235a62012-02-21 14:32:24 +02003131 goto failed;
3132 }
3133
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003134 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003135 if (!cmd) {
3136 err = -ENOMEM;
3137 goto failed;
3138 }
3139
Johan Hedberg13928972013-03-15 17:07:00 -05003140 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3141
Johan Hedberg890ea892013-03-15 17:06:52 -05003142 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003143
3144 if (lmp_bredr_capable(hdev)) {
3145 update_name(&req);
3146 update_eir(&req);
3147 }
3148
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003149 /* The name is stored in the scan response data and so
3150 * no need to udpate the advertising data here.
3151 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003152 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003153 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003154
Johan Hedberg13928972013-03-15 17:07:00 -05003155 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003156 if (err < 0)
3157 mgmt_pending_remove(cmd);
3158
3159failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003160 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003161 return err;
3162}
3163
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003164static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003165 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003166{
Szymon Jancc35938b2011-03-22 13:12:21 +01003167 struct pending_cmd *cmd;
3168 int err;
3169
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003170 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003171
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003172 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003173
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003174 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003175 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003176 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003177 goto unlock;
3178 }
3179
Andre Guedes9a1a1992012-07-24 15:03:48 -03003180 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003181 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003182 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003183 goto unlock;
3184 }
3185
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003186 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003187 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003188 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003189 goto unlock;
3190 }
3191
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003192 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003193 if (!cmd) {
3194 err = -ENOMEM;
3195 goto unlock;
3196 }
3197
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003198 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
3199 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
3200 0, NULL);
3201 else
3202 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3203
Szymon Jancc35938b2011-03-22 13:12:21 +01003204 if (err < 0)
3205 mgmt_pending_remove(cmd);
3206
3207unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003208 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003209 return err;
3210}
3211
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003212static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003213 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003214{
Szymon Janc2763eda2011-03-22 13:12:22 +01003215 int err;
3216
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003217 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003218
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003219 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003220
Marcel Holtmannec109112014-01-10 02:07:30 -08003221 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3222 struct mgmt_cp_add_remote_oob_data *cp = data;
3223 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003224
Marcel Holtmannec109112014-01-10 02:07:30 -08003225 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
3226 cp->hash, cp->randomizer);
3227 if (err < 0)
3228 status = MGMT_STATUS_FAILED;
3229 else
3230 status = MGMT_STATUS_SUCCESS;
3231
3232 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3233 status, &cp->addr, sizeof(cp->addr));
3234 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3235 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
3236 u8 status;
3237
3238 err = hci_add_remote_oob_ext_data(hdev, &cp->addr.bdaddr,
3239 cp->hash192,
3240 cp->randomizer192,
3241 cp->hash256,
3242 cp->randomizer256);
3243 if (err < 0)
3244 status = MGMT_STATUS_FAILED;
3245 else
3246 status = MGMT_STATUS_SUCCESS;
3247
3248 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3249 status, &cp->addr, sizeof(cp->addr));
3250 } else {
3251 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
3252 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3253 MGMT_STATUS_INVALID_PARAMS);
3254 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003255
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003256 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003257 return err;
3258}
3259
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003260static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003261 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003262{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003263 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003264 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003265 int err;
3266
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003267 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003268
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003269 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003270
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003271 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003272 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003273 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003274 else
Szymon Janca6785be2012-12-13 15:11:21 +01003275 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003276
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003277 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003278 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003279
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003280 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003281 return err;
3282}
3283
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003284static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3285{
3286 struct pending_cmd *cmd;
3287 u8 type;
3288 int err;
3289
3290 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3291
3292 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3293 if (!cmd)
3294 return -ENOENT;
3295
3296 type = hdev->discovery.type;
3297
3298 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3299 &type, sizeof(type));
3300 mgmt_pending_remove(cmd);
3301
3302 return err;
3303}
3304
Andre Guedes7c307722013-04-30 15:29:28 -03003305static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3306{
3307 BT_DBG("status %d", status);
3308
3309 if (status) {
3310 hci_dev_lock(hdev);
3311 mgmt_start_discovery_failed(hdev, status);
3312 hci_dev_unlock(hdev);
3313 return;
3314 }
3315
3316 hci_dev_lock(hdev);
3317 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3318 hci_dev_unlock(hdev);
3319
3320 switch (hdev->discovery.type) {
3321 case DISCOV_TYPE_LE:
3322 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003323 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003324 break;
3325
3326 case DISCOV_TYPE_INTERLEAVED:
3327 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003328 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003329 break;
3330
3331 case DISCOV_TYPE_BREDR:
3332 break;
3333
3334 default:
3335 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3336 }
3337}
3338
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003339static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003340 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003341{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003342 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003343 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003344 struct hci_cp_le_set_scan_param param_cp;
3345 struct hci_cp_le_set_scan_enable enable_cp;
3346 struct hci_cp_inquiry inq_cp;
3347 struct hci_request req;
3348 /* General inquiry access code (GIAC) */
3349 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedbergd9483942014-02-23 19:42:24 +02003350 u8 status, own_addr_type;
Johan Hedberg14a53662011-04-27 10:29:56 -04003351 int err;
3352
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003353 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003354
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003355 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003356
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003357 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003358 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003359 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003360 goto failed;
3361 }
3362
Andre Guedes642be6c2012-03-21 00:03:37 -03003363 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3364 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3365 MGMT_STATUS_BUSY);
3366 goto failed;
3367 }
3368
Johan Hedbergff9ef572012-01-04 14:23:45 +02003369 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003370 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003371 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003372 goto failed;
3373 }
3374
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003375 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003376 if (!cmd) {
3377 err = -ENOMEM;
3378 goto failed;
3379 }
3380
Andre Guedes4aab14e2012-02-17 20:39:36 -03003381 hdev->discovery.type = cp->type;
3382
Andre Guedes7c307722013-04-30 15:29:28 -03003383 hci_req_init(&req, hdev);
3384
Andre Guedes4aab14e2012-02-17 20:39:36 -03003385 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003386 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003387 status = mgmt_bredr_support(hdev);
3388 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003389 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003390 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003391 mgmt_pending_remove(cmd);
3392 goto failed;
3393 }
3394
Andre Guedes7c307722013-04-30 15:29:28 -03003395 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3396 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3397 MGMT_STATUS_BUSY);
3398 mgmt_pending_remove(cmd);
3399 goto failed;
3400 }
3401
3402 hci_inquiry_cache_flush(hdev);
3403
3404 memset(&inq_cp, 0, sizeof(inq_cp));
3405 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003406 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003407 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003408 break;
3409
3410 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003411 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003412 status = mgmt_le_support(hdev);
3413 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003414 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003415 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003416 mgmt_pending_remove(cmd);
3417 goto failed;
3418 }
3419
Andre Guedes7c307722013-04-30 15:29:28 -03003420 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003421 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003422 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3423 MGMT_STATUS_NOT_SUPPORTED);
3424 mgmt_pending_remove(cmd);
3425 goto failed;
3426 }
3427
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003428 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003429 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3430 MGMT_STATUS_REJECTED);
3431 mgmt_pending_remove(cmd);
3432 goto failed;
3433 }
3434
3435 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3436 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3437 MGMT_STATUS_BUSY);
3438 mgmt_pending_remove(cmd);
3439 goto failed;
3440 }
3441
3442 memset(&param_cp, 0, sizeof(param_cp));
Johan Hedbergd9483942014-02-23 19:42:24 +02003443
Marcel Holtmann94b1fc92014-02-23 20:25:54 -08003444 /* All active scans will be done with either a resolvable
3445 * private address (when privacy feature has been enabled)
3446 * or unresolvable private address.
3447 */
3448 err = hci_update_random_address(&req, true, &own_addr_type);
Johan Hedbergd9483942014-02-23 19:42:24 +02003449 if (err < 0) {
3450 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3451 MGMT_STATUS_FAILED);
3452 mgmt_pending_remove(cmd);
3453 goto failed;
3454 }
3455
Andre Guedes7c307722013-04-30 15:29:28 -03003456 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003457 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3458 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Johan Hedbergd9483942014-02-23 19:42:24 +02003459 param_cp.own_address_type = own_addr_type;
Andre Guedes7c307722013-04-30 15:29:28 -03003460 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3461 &param_cp);
3462
3463 memset(&enable_cp, 0, sizeof(enable_cp));
3464 enable_cp.enable = LE_SCAN_ENABLE;
3465 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3466 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3467 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003468 break;
3469
Andre Guedesf39799f2012-02-17 20:39:35 -03003470 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003471 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3472 MGMT_STATUS_INVALID_PARAMS);
3473 mgmt_pending_remove(cmd);
3474 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003475 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003476
Andre Guedes7c307722013-04-30 15:29:28 -03003477 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003478 if (err < 0)
3479 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003480 else
3481 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003482
3483failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003484 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003485 return err;
3486}
3487
Andre Guedes1183fdc2013-04-30 15:29:35 -03003488static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3489{
3490 struct pending_cmd *cmd;
3491 int err;
3492
3493 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3494 if (!cmd)
3495 return -ENOENT;
3496
3497 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3498 &hdev->discovery.type, sizeof(hdev->discovery.type));
3499 mgmt_pending_remove(cmd);
3500
3501 return err;
3502}
3503
Andre Guedes0e05bba2013-04-30 15:29:33 -03003504static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3505{
3506 BT_DBG("status %d", status);
3507
3508 hci_dev_lock(hdev);
3509
3510 if (status) {
3511 mgmt_stop_discovery_failed(hdev, status);
3512 goto unlock;
3513 }
3514
3515 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3516
3517unlock:
3518 hci_dev_unlock(hdev);
3519}
3520
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003521static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003522 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003523{
Johan Hedbergd9306502012-02-20 23:25:18 +02003524 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003525 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003526 struct hci_cp_remote_name_req_cancel cp;
3527 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003528 struct hci_request req;
3529 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003530 int err;
3531
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003532 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003533
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003534 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003535
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003536 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003537 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003538 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3539 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003540 goto unlock;
3541 }
3542
3543 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003544 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003545 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3546 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003547 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003548 }
3549
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003550 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003551 if (!cmd) {
3552 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003553 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003554 }
3555
Andre Guedes0e05bba2013-04-30 15:29:33 -03003556 hci_req_init(&req, hdev);
3557
Andre Guedese0d9727e2012-03-20 15:15:36 -03003558 switch (hdev->discovery.state) {
3559 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003560 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3561 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3562 } else {
3563 cancel_delayed_work(&hdev->le_scan_disable);
3564
3565 memset(&enable_cp, 0, sizeof(enable_cp));
3566 enable_cp.enable = LE_SCAN_DISABLE;
3567 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3568 sizeof(enable_cp), &enable_cp);
3569 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003570
Andre Guedese0d9727e2012-03-20 15:15:36 -03003571 break;
3572
3573 case DISCOVERY_RESOLVING:
3574 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003575 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003576 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003577 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003578 err = cmd_complete(sk, hdev->id,
3579 MGMT_OP_STOP_DISCOVERY, 0,
3580 &mgmt_cp->type,
3581 sizeof(mgmt_cp->type));
3582 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3583 goto unlock;
3584 }
3585
3586 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003587 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3588 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003589
3590 break;
3591
3592 default:
3593 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003594
3595 mgmt_pending_remove(cmd);
3596 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3597 MGMT_STATUS_FAILED, &mgmt_cp->type,
3598 sizeof(mgmt_cp->type));
3599 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003600 }
3601
Andre Guedes0e05bba2013-04-30 15:29:33 -03003602 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003603 if (err < 0)
3604 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003605 else
3606 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003607
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003608unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003609 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003610 return err;
3611}
3612
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003613static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003614 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003615{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003616 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003617 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003618 int err;
3619
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003620 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003621
Johan Hedberg561aafb2012-01-04 13:31:59 +02003622 hci_dev_lock(hdev);
3623
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003624 if (!hci_discovery_active(hdev)) {
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_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003627 goto failed;
3628 }
3629
Johan Hedberga198e7b2012-02-17 14:27:06 +02003630 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003631 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003632 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003633 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003634 goto failed;
3635 }
3636
3637 if (cp->name_known) {
3638 e->name_state = NAME_KNOWN;
3639 list_del(&e->list);
3640 } else {
3641 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003642 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003643 }
3644
Johan Hedberge3846622013-01-09 15:29:33 +02003645 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3646 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003647
3648failed:
3649 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003650 return err;
3651}
3652
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003653static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003654 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003655{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003656 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003657 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003658 int err;
3659
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003660 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003661
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003662 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003663 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3664 MGMT_STATUS_INVALID_PARAMS,
3665 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003666
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003667 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003668
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003669 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003670 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003671 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003672 else
Szymon Janca6785be2012-12-13 15:11:21 +01003673 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003674
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003675 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003676 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003677
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003678 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003679
3680 return err;
3681}
3682
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003683static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003684 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003685{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003686 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003687 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003688 int err;
3689
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003690 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003691
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003692 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003693 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3694 MGMT_STATUS_INVALID_PARAMS,
3695 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003696
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003697 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003698
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003699 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003700 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003701 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003702 else
Szymon Janca6785be2012-12-13 15:11:21 +01003703 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003704
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003705 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003706 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003707
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003708 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003709
3710 return err;
3711}
3712
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003713static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3714 u16 len)
3715{
3716 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003717 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003718 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003719 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003720
3721 BT_DBG("%s", hdev->name);
3722
Szymon Jancc72d4b82012-03-16 16:02:57 +01003723 source = __le16_to_cpu(cp->source);
3724
3725 if (source > 0x0002)
3726 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3727 MGMT_STATUS_INVALID_PARAMS);
3728
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003729 hci_dev_lock(hdev);
3730
Szymon Jancc72d4b82012-03-16 16:02:57 +01003731 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003732 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3733 hdev->devid_product = __le16_to_cpu(cp->product);
3734 hdev->devid_version = __le16_to_cpu(cp->version);
3735
3736 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3737
Johan Hedberg890ea892013-03-15 17:06:52 -05003738 hci_req_init(&req, hdev);
3739 update_eir(&req);
3740 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003741
3742 hci_dev_unlock(hdev);
3743
3744 return err;
3745}
3746
Johan Hedberg4375f102013-09-25 13:26:10 +03003747static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3748{
3749 struct cmd_lookup match = { NULL, hdev };
3750
3751 if (status) {
3752 u8 mgmt_err = mgmt_status(status);
3753
3754 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3755 cmd_status_rsp, &mgmt_err);
3756 return;
3757 }
3758
3759 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3760 &match);
3761
3762 new_settings(hdev, match.sk);
3763
3764 if (match.sk)
3765 sock_put(match.sk);
3766}
3767
Marcel Holtmann21b51872013-10-10 09:47:53 -07003768static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3769 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003770{
3771 struct mgmt_mode *cp = data;
3772 struct pending_cmd *cmd;
3773 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003774 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003775 int err;
3776
3777 BT_DBG("request for %s", hdev->name);
3778
Johan Hedberge6fe7982013-10-02 15:45:22 +03003779 status = mgmt_le_support(hdev);
3780 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003781 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003782 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003783
3784 if (cp->val != 0x00 && cp->val != 0x01)
3785 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3786 MGMT_STATUS_INVALID_PARAMS);
3787
3788 hci_dev_lock(hdev);
3789
3790 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003791 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003792
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003793 /* The following conditions are ones which mean that we should
3794 * not do any HCI communication but directly send a mgmt
3795 * response to user space (after toggling the flag if
3796 * necessary).
3797 */
3798 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003799 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003800 bool changed = false;
3801
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003802 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3803 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003804 changed = true;
3805 }
3806
3807 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3808 if (err < 0)
3809 goto unlock;
3810
3811 if (changed)
3812 err = new_settings(hdev, sk);
3813
3814 goto unlock;
3815 }
3816
3817 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3818 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3819 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3820 MGMT_STATUS_BUSY);
3821 goto unlock;
3822 }
3823
3824 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3825 if (!cmd) {
3826 err = -ENOMEM;
3827 goto unlock;
3828 }
3829
3830 hci_req_init(&req, hdev);
3831
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003832 if (val)
3833 enable_advertising(&req);
3834 else
3835 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003836
3837 err = hci_req_run(&req, set_advertising_complete);
3838 if (err < 0)
3839 mgmt_pending_remove(cmd);
3840
3841unlock:
3842 hci_dev_unlock(hdev);
3843 return err;
3844}
3845
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003846static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3847 void *data, u16 len)
3848{
3849 struct mgmt_cp_set_static_address *cp = data;
3850 int err;
3851
3852 BT_DBG("%s", hdev->name);
3853
Marcel Holtmann62af4442013-10-02 22:10:32 -07003854 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003855 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003856 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003857
3858 if (hdev_is_powered(hdev))
3859 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3860 MGMT_STATUS_REJECTED);
3861
3862 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3863 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3864 return cmd_status(sk, hdev->id,
3865 MGMT_OP_SET_STATIC_ADDRESS,
3866 MGMT_STATUS_INVALID_PARAMS);
3867
3868 /* Two most significant bits shall be set */
3869 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3870 return cmd_status(sk, hdev->id,
3871 MGMT_OP_SET_STATIC_ADDRESS,
3872 MGMT_STATUS_INVALID_PARAMS);
3873 }
3874
3875 hci_dev_lock(hdev);
3876
3877 bacpy(&hdev->static_addr, &cp->bdaddr);
3878
3879 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3880
3881 hci_dev_unlock(hdev);
3882
3883 return err;
3884}
3885
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003886static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3887 void *data, u16 len)
3888{
3889 struct mgmt_cp_set_scan_params *cp = data;
3890 __u16 interval, window;
3891 int err;
3892
3893 BT_DBG("%s", hdev->name);
3894
3895 if (!lmp_le_capable(hdev))
3896 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3897 MGMT_STATUS_NOT_SUPPORTED);
3898
3899 interval = __le16_to_cpu(cp->interval);
3900
3901 if (interval < 0x0004 || interval > 0x4000)
3902 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3903 MGMT_STATUS_INVALID_PARAMS);
3904
3905 window = __le16_to_cpu(cp->window);
3906
3907 if (window < 0x0004 || window > 0x4000)
3908 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3909 MGMT_STATUS_INVALID_PARAMS);
3910
Marcel Holtmann899e1072013-10-14 09:55:32 -07003911 if (window > interval)
3912 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3913 MGMT_STATUS_INVALID_PARAMS);
3914
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003915 hci_dev_lock(hdev);
3916
3917 hdev->le_scan_interval = interval;
3918 hdev->le_scan_window = window;
3919
3920 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3921
3922 hci_dev_unlock(hdev);
3923
3924 return err;
3925}
3926
Johan Hedberg33e38b32013-03-15 17:07:05 -05003927static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3928{
3929 struct pending_cmd *cmd;
3930
3931 BT_DBG("status 0x%02x", status);
3932
3933 hci_dev_lock(hdev);
3934
3935 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3936 if (!cmd)
3937 goto unlock;
3938
3939 if (status) {
3940 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3941 mgmt_status(status));
3942 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003943 struct mgmt_mode *cp = cmd->param;
3944
3945 if (cp->val)
3946 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3947 else
3948 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3949
Johan Hedberg33e38b32013-03-15 17:07:05 -05003950 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3951 new_settings(hdev, cmd->sk);
3952 }
3953
3954 mgmt_pending_remove(cmd);
3955
3956unlock:
3957 hci_dev_unlock(hdev);
3958}
3959
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003960static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003961 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003962{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003963 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003964 struct pending_cmd *cmd;
3965 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003966 int err;
3967
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003968 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003969
Johan Hedberg56f87902013-10-02 13:43:13 +03003970 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3971 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003972 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3973 MGMT_STATUS_NOT_SUPPORTED);
3974
Johan Hedberga7e80f22013-01-09 16:05:19 +02003975 if (cp->val != 0x00 && cp->val != 0x01)
3976 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3977 MGMT_STATUS_INVALID_PARAMS);
3978
Johan Hedberg5400c042012-02-21 16:40:33 +02003979 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003980 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003981 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003982
3983 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003984 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003985 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003986
3987 hci_dev_lock(hdev);
3988
Johan Hedberg05cbf292013-03-15 17:07:07 -05003989 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3990 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3991 MGMT_STATUS_BUSY);
3992 goto unlock;
3993 }
3994
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003995 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3996 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3997 hdev);
3998 goto unlock;
3999 }
4000
Johan Hedberg33e38b32013-03-15 17:07:05 -05004001 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
4002 data, len);
4003 if (!cmd) {
4004 err = -ENOMEM;
4005 goto unlock;
4006 }
4007
4008 hci_req_init(&req, hdev);
4009
Johan Hedberg406d7802013-03-15 17:07:09 -05004010 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004011
4012 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004013 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004014 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004015 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004016 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03004017 }
4018
Johan Hedberg33e38b32013-03-15 17:07:05 -05004019unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03004020 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05004021
Antti Julkuf6422ec2011-06-22 13:11:56 +03004022 return err;
4023}
4024
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03004025static void set_bredr_scan(struct hci_request *req)
4026{
4027 struct hci_dev *hdev = req->hdev;
4028 u8 scan = 0;
4029
4030 /* Ensure that fast connectable is disabled. This function will
4031 * not do anything if the page scan parameters are already what
4032 * they should be.
4033 */
4034 write_fast_connectable(req, false);
4035
4036 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4037 scan |= SCAN_PAGE;
4038 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4039 scan |= SCAN_INQUIRY;
4040
4041 if (scan)
4042 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
4043}
4044
Johan Hedberg0663ca22013-10-02 13:43:14 +03004045static void set_bredr_complete(struct hci_dev *hdev, u8 status)
4046{
4047 struct pending_cmd *cmd;
4048
4049 BT_DBG("status 0x%02x", status);
4050
4051 hci_dev_lock(hdev);
4052
4053 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
4054 if (!cmd)
4055 goto unlock;
4056
4057 if (status) {
4058 u8 mgmt_err = mgmt_status(status);
4059
4060 /* We need to restore the flag if related HCI commands
4061 * failed.
4062 */
4063 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4064
4065 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
4066 } else {
4067 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
4068 new_settings(hdev, cmd->sk);
4069 }
4070
4071 mgmt_pending_remove(cmd);
4072
4073unlock:
4074 hci_dev_unlock(hdev);
4075}
4076
4077static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
4078{
4079 struct mgmt_mode *cp = data;
4080 struct pending_cmd *cmd;
4081 struct hci_request req;
4082 int err;
4083
4084 BT_DBG("request for %s", hdev->name);
4085
4086 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
4087 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4088 MGMT_STATUS_NOT_SUPPORTED);
4089
4090 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
4091 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4092 MGMT_STATUS_REJECTED);
4093
4094 if (cp->val != 0x00 && cp->val != 0x01)
4095 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4096 MGMT_STATUS_INVALID_PARAMS);
4097
4098 hci_dev_lock(hdev);
4099
4100 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4101 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4102 goto unlock;
4103 }
4104
4105 if (!hdev_is_powered(hdev)) {
4106 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004107 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4108 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4109 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4110 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
4111 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
4112 }
4113
4114 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4115
4116 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4117 if (err < 0)
4118 goto unlock;
4119
4120 err = new_settings(hdev, sk);
4121 goto unlock;
4122 }
4123
4124 /* Reject disabling when powered on */
4125 if (!cp->val) {
4126 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4127 MGMT_STATUS_REJECTED);
4128 goto unlock;
4129 }
4130
4131 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
4132 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4133 MGMT_STATUS_BUSY);
4134 goto unlock;
4135 }
4136
4137 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4138 if (!cmd) {
4139 err = -ENOMEM;
4140 goto unlock;
4141 }
4142
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004143 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03004144 * generates the correct flags.
4145 */
4146 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4147
4148 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004149
4150 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4151 set_bredr_scan(&req);
4152
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004153 /* Since only the advertising data flags will change, there
4154 * is no need to update the scan response data.
4155 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004156 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004157
Johan Hedberg0663ca22013-10-02 13:43:14 +03004158 err = hci_req_run(&req, set_bredr_complete);
4159 if (err < 0)
4160 mgmt_pending_remove(cmd);
4161
4162unlock:
4163 hci_dev_unlock(hdev);
4164 return err;
4165}
4166
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004167static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4168 void *data, u16 len)
4169{
4170 struct mgmt_mode *cp = data;
4171 struct pending_cmd *cmd;
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004172 u8 val, status;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004173 int err;
4174
4175 BT_DBG("request for %s", hdev->name);
4176
4177 status = mgmt_bredr_support(hdev);
4178 if (status)
4179 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4180 status);
4181
Marcel Holtmann5afeac12014-01-10 02:07:27 -08004182 if (!lmp_sc_capable(hdev) &&
4183 !test_bit(HCI_FORCE_SC, &hdev->dev_flags))
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004184 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4185 MGMT_STATUS_NOT_SUPPORTED);
4186
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004187 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004188 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4189 MGMT_STATUS_INVALID_PARAMS);
4190
4191 hci_dev_lock(hdev);
4192
4193 if (!hdev_is_powered(hdev)) {
4194 bool changed;
4195
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004196 if (cp->val) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004197 changed = !test_and_set_bit(HCI_SC_ENABLED,
4198 &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004199 if (cp->val == 0x02)
4200 set_bit(HCI_SC_ONLY, &hdev->dev_flags);
4201 else
4202 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4203 } else {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004204 changed = test_and_clear_bit(HCI_SC_ENABLED,
4205 &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004206 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4207 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004208
4209 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4210 if (err < 0)
4211 goto failed;
4212
4213 if (changed)
4214 err = new_settings(hdev, sk);
4215
4216 goto failed;
4217 }
4218
4219 if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
4220 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4221 MGMT_STATUS_BUSY);
4222 goto failed;
4223 }
4224
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004225 val = !!cp->val;
4226
4227 if (val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
4228 (cp->val == 0x02) == test_bit(HCI_SC_ONLY, &hdev->dev_flags)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004229 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4230 goto failed;
4231 }
4232
4233 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4234 if (!cmd) {
4235 err = -ENOMEM;
4236 goto failed;
4237 }
4238
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004239 err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004240 if (err < 0) {
4241 mgmt_pending_remove(cmd);
4242 goto failed;
4243 }
4244
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004245 if (cp->val == 0x02)
4246 set_bit(HCI_SC_ONLY, &hdev->dev_flags);
4247 else
4248 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4249
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004250failed:
4251 hci_dev_unlock(hdev);
4252 return err;
4253}
4254
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004255static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4256 void *data, u16 len)
4257{
4258 struct mgmt_mode *cp = data;
4259 bool changed;
4260 int err;
4261
4262 BT_DBG("request for %s", hdev->name);
4263
4264 if (cp->val != 0x00 && cp->val != 0x01)
4265 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4266 MGMT_STATUS_INVALID_PARAMS);
4267
4268 hci_dev_lock(hdev);
4269
4270 if (cp->val)
4271 changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
4272 else
4273 changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
4274
4275 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4276 if (err < 0)
4277 goto unlock;
4278
4279 if (changed)
4280 err = new_settings(hdev, sk);
4281
4282unlock:
4283 hci_dev_unlock(hdev);
4284 return err;
4285}
4286
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004287static int set_privacy(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4288 u16 len)
4289{
4290 struct mgmt_cp_set_privacy *cp = cp_data;
4291 bool changed;
4292 int err;
4293
4294 BT_DBG("request for %s", hdev->name);
4295
4296 if (!lmp_le_capable(hdev))
4297 return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4298 MGMT_STATUS_NOT_SUPPORTED);
4299
4300 if (cp->privacy != 0x00 && cp->privacy != 0x01)
4301 return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4302 MGMT_STATUS_INVALID_PARAMS);
4303
4304 if (hdev_is_powered(hdev))
4305 return cmd_status(sk, hdev->id, MGMT_OP_SET_PRIVACY,
4306 MGMT_STATUS_REJECTED);
4307
4308 hci_dev_lock(hdev);
4309
Johan Hedbergc21c0ea2014-02-24 11:10:30 +02004310 /* If user space supports this command it is also expected to
4311 * handle IRKs. Therefore, set the HCI_RPA_RESOLVING flag.
4312 */
4313 set_bit(HCI_RPA_RESOLVING, &hdev->dev_flags);
4314
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004315 if (cp->privacy) {
4316 changed = !test_and_set_bit(HCI_PRIVACY, &hdev->dev_flags);
4317 memcpy(hdev->irk, cp->irk, sizeof(hdev->irk));
4318 set_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
4319 } else {
4320 changed = test_and_clear_bit(HCI_PRIVACY, &hdev->dev_flags);
4321 memset(hdev->irk, 0, sizeof(hdev->irk));
4322 clear_bit(HCI_RPA_EXPIRED, &hdev->dev_flags);
4323 }
4324
4325 err = send_settings_rsp(sk, MGMT_OP_SET_PRIVACY, hdev);
4326 if (err < 0)
4327 goto unlock;
4328
4329 if (changed)
4330 err = new_settings(hdev, sk);
4331
4332unlock:
4333 hci_dev_unlock(hdev);
4334 return err;
4335}
4336
Johan Hedberg41edf162014-02-18 10:19:35 +02004337static bool irk_is_valid(struct mgmt_irk_info *irk)
4338{
4339 switch (irk->addr.type) {
4340 case BDADDR_LE_PUBLIC:
4341 return true;
4342
4343 case BDADDR_LE_RANDOM:
4344 /* Two most significant bits shall be set */
4345 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4346 return false;
4347 return true;
4348 }
4349
4350 return false;
4351}
4352
4353static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4354 u16 len)
4355{
4356 struct mgmt_cp_load_irks *cp = cp_data;
4357 u16 irk_count, expected_len;
4358 int i, err;
4359
4360 BT_DBG("request for %s", hdev->name);
4361
4362 if (!lmp_le_capable(hdev))
4363 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4364 MGMT_STATUS_NOT_SUPPORTED);
4365
4366 irk_count = __le16_to_cpu(cp->irk_count);
4367
4368 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4369 if (expected_len != len) {
4370 BT_ERR("load_irks: expected %u bytes, got %u bytes",
4371 len, expected_len);
4372 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4373 MGMT_STATUS_INVALID_PARAMS);
4374 }
4375
4376 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4377
4378 for (i = 0; i < irk_count; i++) {
4379 struct mgmt_irk_info *key = &cp->irks[i];
4380
4381 if (!irk_is_valid(key))
4382 return cmd_status(sk, hdev->id,
4383 MGMT_OP_LOAD_IRKS,
4384 MGMT_STATUS_INVALID_PARAMS);
4385 }
4386
4387 hci_dev_lock(hdev);
4388
4389 hci_smp_irks_clear(hdev);
4390
4391 for (i = 0; i < irk_count; i++) {
4392 struct mgmt_irk_info *irk = &cp->irks[i];
4393 u8 addr_type;
4394
4395 if (irk->addr.type == BDADDR_LE_PUBLIC)
4396 addr_type = ADDR_LE_DEV_PUBLIC;
4397 else
4398 addr_type = ADDR_LE_DEV_RANDOM;
4399
4400 hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
4401 BDADDR_ANY);
4402 }
4403
4404 set_bit(HCI_RPA_RESOLVING, &hdev->dev_flags);
4405
4406 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
4407
4408 hci_dev_unlock(hdev);
4409
4410 return err;
4411}
4412
Johan Hedberg3f706b72013-01-20 14:27:16 +02004413static bool ltk_is_valid(struct mgmt_ltk_info *key)
4414{
4415 if (key->master != 0x00 && key->master != 0x01)
4416 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004417
4418 switch (key->addr.type) {
4419 case BDADDR_LE_PUBLIC:
4420 return true;
4421
4422 case BDADDR_LE_RANDOM:
4423 /* Two most significant bits shall be set */
4424 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4425 return false;
4426 return true;
4427 }
4428
4429 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004430}
4431
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004432static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004433 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004434{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004435 struct mgmt_cp_load_long_term_keys *cp = cp_data;
4436 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004437 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004438
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004439 BT_DBG("request for %s", hdev->name);
4440
4441 if (!lmp_le_capable(hdev))
4442 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4443 MGMT_STATUS_NOT_SUPPORTED);
4444
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004445 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004446
4447 expected_len = sizeof(*cp) + key_count *
4448 sizeof(struct mgmt_ltk_info);
4449 if (expected_len != len) {
4450 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004451 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004452 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02004453 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004454 }
4455
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004456 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004457
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004458 for (i = 0; i < key_count; i++) {
4459 struct mgmt_ltk_info *key = &cp->keys[i];
4460
Johan Hedberg3f706b72013-01-20 14:27:16 +02004461 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004462 return cmd_status(sk, hdev->id,
4463 MGMT_OP_LOAD_LONG_TERM_KEYS,
4464 MGMT_STATUS_INVALID_PARAMS);
4465 }
4466
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004467 hci_dev_lock(hdev);
4468
4469 hci_smp_ltks_clear(hdev);
4470
4471 for (i = 0; i < key_count; i++) {
4472 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004473 u8 type, addr_type;
4474
4475 if (key->addr.type == BDADDR_LE_PUBLIC)
4476 addr_type = ADDR_LE_DEV_PUBLIC;
4477 else
4478 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004479
4480 if (key->master)
4481 type = HCI_SMP_LTK;
4482 else
4483 type = HCI_SMP_LTK_SLAVE;
4484
Johan Hedberg35d70272014-02-19 14:57:47 +02004485 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type,
4486 key->type, key->val, key->enc_size, key->ediv,
4487 key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004488 }
4489
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004490 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4491 NULL, 0);
4492
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004493 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004494
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004495 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004496}
4497
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004498static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004499 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4500 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004501 bool var_len;
4502 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004503} mgmt_handlers[] = {
4504 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004505 { read_version, false, MGMT_READ_VERSION_SIZE },
4506 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4507 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4508 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4509 { set_powered, false, MGMT_SETTING_SIZE },
4510 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4511 { set_connectable, false, MGMT_SETTING_SIZE },
4512 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4513 { set_pairable, false, MGMT_SETTING_SIZE },
4514 { set_link_security, false, MGMT_SETTING_SIZE },
4515 { set_ssp, false, MGMT_SETTING_SIZE },
4516 { set_hs, false, MGMT_SETTING_SIZE },
4517 { set_le, false, MGMT_SETTING_SIZE },
4518 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4519 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4520 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4521 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4522 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4523 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4524 { disconnect, false, MGMT_DISCONNECT_SIZE },
4525 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4526 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4527 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4528 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4529 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4530 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4531 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4532 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4533 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4534 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4535 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4536 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
Marcel Holtmannec109112014-01-10 02:07:30 -08004537 { add_remote_oob_data, true, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
Johan Hedbergbe22b542012-03-01 22:24:41 +02004538 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4539 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4540 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4541 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4542 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4543 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004544 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004545 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004546 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004547 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004548 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004549 { set_secure_conn, false, MGMT_SETTING_SIZE },
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004550 { set_debug_keys, false, MGMT_SETTING_SIZE },
Johan Hedberg62b04cd2014-02-23 19:42:27 +02004551 { set_privacy, false, MGMT_SET_PRIVACY_SIZE },
Johan Hedberg41edf162014-02-18 10:19:35 +02004552 { load_irks, true, MGMT_LOAD_IRKS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004553};
4554
4555
Johan Hedberg03811012010-12-08 00:21:06 +02004556int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4557{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004558 void *buf;
4559 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004560 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004561 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004562 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004563 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004564 int err;
4565
4566 BT_DBG("got %zu bytes", msglen);
4567
4568 if (msglen < sizeof(*hdr))
4569 return -EINVAL;
4570
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004571 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004572 if (!buf)
4573 return -ENOMEM;
4574
4575 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4576 err = -EFAULT;
4577 goto done;
4578 }
4579
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004580 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004581 opcode = __le16_to_cpu(hdr->opcode);
4582 index = __le16_to_cpu(hdr->index);
4583 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004584
4585 if (len != msglen - sizeof(*hdr)) {
4586 err = -EINVAL;
4587 goto done;
4588 }
4589
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004590 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004591 hdev = hci_dev_get(index);
4592 if (!hdev) {
4593 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004594 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004595 goto done;
4596 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004597
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004598 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4599 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004600 err = cmd_status(sk, index, opcode,
4601 MGMT_STATUS_INVALID_INDEX);
4602 goto done;
4603 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004604 }
4605
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004606 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004607 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004608 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004609 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004610 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004611 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004612 }
4613
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004614 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004615 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004616 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004617 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004618 goto done;
4619 }
4620
Johan Hedbergbe22b542012-03-01 22:24:41 +02004621 handler = &mgmt_handlers[opcode];
4622
4623 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004624 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004625 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004626 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004627 goto done;
4628 }
4629
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004630 if (hdev)
4631 mgmt_init_hdev(sk, hdev);
4632
4633 cp = buf + sizeof(*hdr);
4634
Johan Hedbergbe22b542012-03-01 22:24:41 +02004635 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004636 if (err < 0)
4637 goto done;
4638
Johan Hedberg03811012010-12-08 00:21:06 +02004639 err = msglen;
4640
4641done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004642 if (hdev)
4643 hci_dev_put(hdev);
4644
Johan Hedberg03811012010-12-08 00:21:06 +02004645 kfree(buf);
4646 return err;
4647}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004648
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004649void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004650{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004651 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004652 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004653
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004654 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004655}
4656
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004657void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004658{
Johan Hedberg5f159032012-03-02 03:13:19 +02004659 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004660
Marcel Holtmann1514b892013-10-06 08:25:01 -07004661 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004662 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004663
Johan Hedberg744cf192011-11-08 20:40:14 +02004664 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004665
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004666 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004667}
4668
Johan Hedberg229ab392013-03-15 17:06:53 -05004669static void powered_complete(struct hci_dev *hdev, u8 status)
4670{
4671 struct cmd_lookup match = { NULL, hdev };
4672
4673 BT_DBG("status 0x%02x", status);
4674
4675 hci_dev_lock(hdev);
4676
4677 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4678
4679 new_settings(hdev, match.sk);
4680
4681 hci_dev_unlock(hdev);
4682
4683 if (match.sk)
4684 sock_put(match.sk);
4685}
4686
Johan Hedberg70da6242013-03-15 17:06:51 -05004687static int powered_update_hci(struct hci_dev *hdev)
4688{
Johan Hedberg890ea892013-03-15 17:06:52 -05004689 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004690 u8 link_sec;
4691
Johan Hedberg890ea892013-03-15 17:06:52 -05004692 hci_req_init(&req, hdev);
4693
Johan Hedberg70da6242013-03-15 17:06:51 -05004694 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4695 !lmp_host_ssp_capable(hdev)) {
4696 u8 ssp = 1;
4697
Johan Hedberg890ea892013-03-15 17:06:52 -05004698 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004699 }
4700
Johan Hedbergc73eee92013-04-19 18:35:21 +03004701 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4702 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004703 struct hci_cp_write_le_host_supported cp;
4704
4705 cp.le = 1;
4706 cp.simul = lmp_le_br_capable(hdev);
4707
4708 /* Check first if we already have the right
4709 * host state (host features set)
4710 */
4711 if (cp.le != lmp_host_le_capable(hdev) ||
4712 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004713 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4714 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004715 }
4716
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004717 if (lmp_le_capable(hdev)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004718 /* Make sure the controller has a good default for
4719 * advertising data. This also applies to the case
4720 * where BR/EDR was toggled during the AUTO_OFF phase.
4721 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004722 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004723 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004724 update_scan_rsp_data(&req);
4725 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004726
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004727 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4728 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004729 }
4730
Johan Hedberg70da6242013-03-15 17:06:51 -05004731 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4732 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004733 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4734 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004735
4736 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004737 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4738 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004739 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004740 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004741 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004742 }
4743
Johan Hedberg229ab392013-03-15 17:06:53 -05004744 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004745}
4746
Johan Hedberg744cf192011-11-08 20:40:14 +02004747int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004748{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004749 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004750 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4751 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004752 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004753
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004754 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4755 return 0;
4756
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004757 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004758 if (powered_update_hci(hdev) == 0)
4759 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004760
Johan Hedberg229ab392013-03-15 17:06:53 -05004761 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4762 &match);
4763 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004764 }
4765
Johan Hedberg229ab392013-03-15 17:06:53 -05004766 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4767 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4768
4769 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4770 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4771 zero_cod, sizeof(zero_cod), NULL);
4772
4773new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004774 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004775
4776 if (match.sk)
4777 sock_put(match.sk);
4778
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004779 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004780}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004781
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004782void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004783{
4784 struct pending_cmd *cmd;
4785 u8 status;
4786
4787 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4788 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004789 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004790
4791 if (err == -ERFKILL)
4792 status = MGMT_STATUS_RFKILLED;
4793 else
4794 status = MGMT_STATUS_FAILED;
4795
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004796 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004797
4798 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004799}
4800
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004801void mgmt_discoverable_timeout(struct hci_dev *hdev)
4802{
4803 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004804
4805 hci_dev_lock(hdev);
4806
4807 /* When discoverable timeout triggers, then just make sure
4808 * the limited discoverable flag is cleared. Even in the case
4809 * of a timeout triggered from general discoverable, it is
4810 * safe to unconditionally clear the flag.
4811 */
4812 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004813 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004814
4815 hci_req_init(&req, hdev);
Johan Hedberg4b580612013-10-19 23:38:21 +03004816 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4817 u8 scan = SCAN_PAGE;
4818 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
4819 sizeof(scan), &scan);
4820 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004821 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004822 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004823 hci_req_run(&req, NULL);
4824
4825 hdev->discov_timeout = 0;
4826
Johan Hedberg9a43e252013-10-20 19:00:07 +03004827 new_settings(hdev, NULL);
4828
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004829 hci_dev_unlock(hdev);
4830}
4831
Marcel Holtmann86a75642013-10-15 06:33:54 -07004832void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004833{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004834 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004835
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004836 /* Nothing needed here if there's a pending command since that
4837 * commands request completion callback takes care of everything
4838 * necessary.
4839 */
4840 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004841 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004842
Johan Hedbergbd107992014-02-24 14:52:19 +02004843 /* Powering off may clear the scan mode - don't let that interfere */
4844 if (!discoverable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4845 return;
4846
Johan Hedberg9a43e252013-10-20 19:00:07 +03004847 if (discoverable) {
Marcel Holtmann86a75642013-10-15 06:33:54 -07004848 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004849 } else {
4850 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmann86a75642013-10-15 06:33:54 -07004851 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004852 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004853
Johan Hedberg9a43e252013-10-20 19:00:07 +03004854 if (changed) {
4855 struct hci_request req;
4856
4857 /* In case this change in discoverable was triggered by
4858 * a disabling of connectable there could be a need to
4859 * update the advertising flags.
4860 */
4861 hci_req_init(&req, hdev);
4862 update_adv_data(&req);
4863 hci_req_run(&req, NULL);
4864
Marcel Holtmann86a75642013-10-15 06:33:54 -07004865 new_settings(hdev, NULL);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004866 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004867}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004868
Marcel Holtmanna3309162013-10-15 06:33:55 -07004869void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004870{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004871 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004872
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004873 /* Nothing needed here if there's a pending command since that
4874 * commands request completion callback takes care of everything
4875 * necessary.
4876 */
4877 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004878 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004879
Johan Hedbergce3f24c2014-02-24 14:52:20 +02004880 /* Powering off may clear the scan mode - don't let that interfere */
4881 if (!connectable && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4882 return;
4883
Marcel Holtmanna3309162013-10-15 06:33:55 -07004884 if (connectable)
4885 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4886 else
4887 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004888
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004889 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004890 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004891}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004892
Johan Hedberg778b2352014-02-24 14:52:17 +02004893void mgmt_advertising(struct hci_dev *hdev, u8 advertising)
4894{
Johan Hedberg7c4cfab2014-02-24 14:52:21 +02004895 /* Powering off may stop advertising - don't let that interfere */
4896 if (!advertising && mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4897 return;
4898
Johan Hedberg778b2352014-02-24 14:52:17 +02004899 if (advertising)
4900 set_bit(HCI_ADVERTISING, &hdev->dev_flags);
4901 else
4902 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
4903}
4904
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004905void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004906{
Johan Hedbergca69b792011-11-11 18:10:00 +02004907 u8 mgmt_err = mgmt_status(status);
4908
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004909 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004910 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004911 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004912
4913 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004914 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004915 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004916}
4917
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004918void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4919 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004920{
Johan Hedberg86742e12011-11-07 23:13:38 +02004921 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004922
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004923 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004924
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004925 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004926 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004927 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004928 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004929 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004930 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004931
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004932 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004933}
Johan Hedbergf7520542011-01-20 12:34:39 +02004934
Johan Hedbergba74b662014-02-19 14:57:45 +02004935void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004936{
4937 struct mgmt_ev_new_long_term_key ev;
4938
4939 memset(&ev, 0, sizeof(ev));
4940
Marcel Holtmann5192d302014-02-19 17:11:58 -08004941 /* Devices using resolvable or non-resolvable random addresses
4942 * without providing an indentity resolving key don't require
4943 * to store long term keys. Their addresses will change the
4944 * next time around.
4945 *
4946 * Only when a remote device provides an identity address
4947 * make sure the long term key is stored. If the remote
4948 * identity is known, the long term keys are internally
4949 * mapped to the identity address. So allow static random
4950 * and public addresses here.
4951 */
Johan Hedbergba74b662014-02-19 14:57:45 +02004952 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
4953 (key->bdaddr.b[5] & 0xc0) != 0xc0)
4954 ev.store_hint = 0x00;
4955 else
4956 ev.store_hint = 0x01;
4957
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004958 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004959 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Marcel Holtmannd40f3ee2014-01-31 18:42:17 -08004960 ev.key.type = key->authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004961 ev.key.enc_size = key->enc_size;
4962 ev.key.ediv = key->ediv;
4963
4964 if (key->type == HCI_SMP_LTK)
4965 ev.key.master = 1;
4966
4967 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4968 memcpy(ev.key.val, key->val, sizeof(key->val));
4969
Marcel Holtmann083368f2013-10-15 14:26:29 -07004970 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004971}
4972
Johan Hedberg95fbac82014-02-19 15:18:31 +02004973void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk)
4974{
4975 struct mgmt_ev_new_irk ev;
4976
4977 memset(&ev, 0, sizeof(ev));
4978
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08004979 /* For identity resolving keys from devices that are already
4980 * using a public address or static random address, do not
4981 * ask for storing this key. The identity resolving key really
4982 * is only mandatory for devices using resovlable random
4983 * addresses.
4984 *
4985 * Storing all identity resolving keys has the downside that
4986 * they will be also loaded on next boot of they system. More
4987 * identity resolving keys, means more time during scanning is
4988 * needed to actually resolve these addresses.
4989 */
4990 if (bacmp(&irk->rpa, BDADDR_ANY))
4991 ev.store_hint = 0x01;
4992 else
4993 ev.store_hint = 0x00;
4994
Johan Hedberg95fbac82014-02-19 15:18:31 +02004995 bacpy(&ev.rpa, &irk->rpa);
4996 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
4997 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
4998 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
4999
5000 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
5001}
5002
Marcel Holtmann94933992013-10-15 10:26:39 -07005003static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
5004 u8 data_len)
5005{
5006 eir[eir_len++] = sizeof(type) + data_len;
5007 eir[eir_len++] = type;
5008 memcpy(&eir[eir_len], data, data_len);
5009 eir_len += data_len;
5010
5011 return eir_len;
5012}
5013
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07005014void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5015 u8 addr_type, u32 flags, u8 *name, u8 name_len,
5016 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02005017{
Johan Hedbergb644ba32012-01-17 21:48:47 +02005018 char buf[512];
5019 struct mgmt_ev_device_connected *ev = (void *) buf;
5020 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02005021
Johan Hedbergb644ba32012-01-17 21:48:47 +02005022 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005023 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02005024
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02005025 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02005026
Johan Hedbergb644ba32012-01-17 21:48:47 +02005027 if (name_len > 0)
5028 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005029 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005030
5031 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08005032 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005033 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005034
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005035 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005036
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07005037 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
5038 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02005039}
5040
Johan Hedberg8962ee72011-01-20 12:40:27 +02005041static void disconnect_rsp(struct pending_cmd *cmd, void *data)
5042{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01005043 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005044 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02005045 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005046
Johan Hedberg88c3df12012-02-09 14:27:38 +02005047 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5048 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005049
Johan Hedbergaee9b212012-02-18 15:07:59 +02005050 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005051 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02005052
5053 *sk = cmd->sk;
5054 sock_hold(*sk);
5055
Johan Hedberga664b5b2011-02-19 12:06:02 -03005056 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005057}
5058
Johan Hedberg124f6e32012-02-09 13:50:12 +02005059static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02005060{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02005061 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02005062 struct mgmt_cp_unpair_device *cp = cmd->param;
5063 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02005064
5065 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02005066 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
5067 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02005068
Johan Hedbergb1078ad2012-02-09 17:21:16 +02005069 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
5070
Johan Hedbergaee9b212012-02-18 15:07:59 +02005071 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02005072
5073 mgmt_pending_remove(cmd);
5074}
5075
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07005076void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02005077 u8 link_type, u8 addr_type, u8 reason,
5078 bool mgmt_connected)
Johan Hedbergf7520542011-01-20 12:34:39 +02005079{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02005080 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8b064a32014-02-24 14:52:22 +02005081 struct pending_cmd *power_off;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005082 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005083
Johan Hedberg8b064a32014-02-24 14:52:22 +02005084 power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
5085 if (power_off) {
5086 struct mgmt_mode *cp = power_off->param;
5087
5088 /* The connection is still in hci_conn_hash so test for 1
5089 * instead of 0 to know if this is the last one.
5090 */
5091 if (!cp->val && hci_conn_count(hdev) == 1)
5092 queue_work(hdev->req_workqueue, &hdev->power_off.work);
5093 }
5094
Johan Hedberg12d4a3b2014-02-24 14:52:18 +02005095 if (!mgmt_connected)
5096 return;
5097
Andre Guedes57eb7762013-10-30 19:01:41 -03005098 if (link_type != ACL_LINK && link_type != LE_LINK)
5099 return;
5100
Johan Hedberg744cf192011-11-08 20:40:14 +02005101 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02005102
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02005103 bacpy(&ev.addr.bdaddr, bdaddr);
5104 ev.addr.type = link_to_bdaddr(link_type, addr_type);
5105 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02005106
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07005107 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005108
5109 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01005110 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005111
Johan Hedberg124f6e32012-02-09 13:50:12 +02005112 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005113 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005114}
5115
Marcel Holtmann78929242013-10-06 23:55:47 -07005116void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
5117 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02005118{
Andre Guedes3655bba2013-10-30 19:01:40 -03005119 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
5120 struct mgmt_cp_disconnect *cp;
Johan Hedberg88c3df12012-02-09 14:27:38 +02005121 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005122 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005123
Jefferson Delfes36a75f12012-09-18 13:36:54 -04005124 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
5125 hdev);
5126
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005127 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02005128 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07005129 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02005130
Andre Guedes3655bba2013-10-30 19:01:40 -03005131 cp = cmd->param;
5132
5133 if (bacmp(bdaddr, &cp->addr.bdaddr))
5134 return;
5135
5136 if (cp->addr.type != bdaddr_type)
5137 return;
5138
Johan Hedberg88c3df12012-02-09 14:27:38 +02005139 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes3655bba2013-10-30 19:01:40 -03005140 rp.addr.type = bdaddr_type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02005141
Marcel Holtmann78929242013-10-06 23:55:47 -07005142 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
5143 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02005144
Johan Hedberga664b5b2011-02-19 12:06:02 -03005145 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02005146}
Johan Hedberg17d5c042011-01-22 06:09:08 +02005147
Marcel Holtmann445608d2013-10-06 23:55:48 -07005148void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5149 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02005150{
5151 struct mgmt_ev_connect_failed ev;
5152
Johan Hedberg4c659c32011-11-07 23:13:39 +02005153 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005154 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02005155 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02005156
Marcel Holtmann445608d2013-10-06 23:55:48 -07005157 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02005158}
Johan Hedberg980e1a52011-01-22 06:10:07 +02005159
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07005160void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02005161{
5162 struct mgmt_ev_pin_code_request ev;
5163
Johan Hedbergd8457692012-02-17 14:24:57 +02005164 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03005165 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02005166 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005167
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07005168 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005169}
5170
Marcel Holtmanne669cf82013-10-15 14:26:21 -07005171void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
5172 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02005173{
5174 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005175 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005176
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005177 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005178 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07005179 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005180
Johan Hedbergd8457692012-02-17 14:24:57 +02005181 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03005182 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005183
Marcel Holtmanne669cf82013-10-15 14:26:21 -07005184 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
5185 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02005186
Johan Hedberga664b5b2011-02-19 12:06:02 -03005187 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005188}
5189
Marcel Holtmann3eb38522013-10-15 14:26:22 -07005190void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
5191 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02005192{
5193 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005194 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005195
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005196 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005197 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07005198 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005199
Johan Hedbergd8457692012-02-17 14:24:57 +02005200 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03005201 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005202
Marcel Holtmann3eb38522013-10-15 14:26:22 -07005203 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
5204 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02005205
Johan Hedberga664b5b2011-02-19 12:06:02 -03005206 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005207}
Johan Hedberga5c29682011-02-19 12:05:57 -03005208
Johan Hedberg744cf192011-11-08 20:40:14 +02005209int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005210 u8 link_type, u8 addr_type, __le32 value,
5211 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03005212{
5213 struct mgmt_ev_user_confirm_request ev;
5214
Johan Hedberg744cf192011-11-08 20:40:14 +02005215 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03005216
Johan Hedberg272d90d2012-02-09 15:26:12 +02005217 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005218 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07005219 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02005220 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03005221
Johan Hedberg744cf192011-11-08 20:40:14 +02005222 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005223 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03005224}
5225
Johan Hedberg272d90d2012-02-09 15:26:12 +02005226int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03005227 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08005228{
5229 struct mgmt_ev_user_passkey_request ev;
5230
5231 BT_DBG("%s", hdev->name);
5232
Johan Hedberg272d90d2012-02-09 15:26:12 +02005233 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005234 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08005235
5236 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005237 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08005238}
5239
Brian Gix0df4c182011-11-16 13:53:13 -08005240static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03005241 u8 link_type, u8 addr_type, u8 status,
5242 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03005243{
5244 struct pending_cmd *cmd;
5245 struct mgmt_rp_user_confirm_reply rp;
5246 int err;
5247
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005248 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03005249 if (!cmd)
5250 return -ENOENT;
5251
Johan Hedberg272d90d2012-02-09 15:26:12 +02005252 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005253 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02005254 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005255 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03005256
Johan Hedberga664b5b2011-02-19 12:06:02 -03005257 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03005258
5259 return err;
5260}
5261
Johan Hedberg744cf192011-11-08 20:40:14 +02005262int mgmt_user_confirm_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 F. Padovan04124682012-03-08 01:25:00 -03005266 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03005267}
5268
Johan Hedberg272d90d2012-02-09 15:26:12 +02005269int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005270 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03005271{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005272 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03005273 status,
5274 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03005275}
Johan Hedberg2a611692011-02-19 12:06:00 -03005276
Brian Gix604086b2011-11-23 08:28:33 -08005277int mgmt_user_passkey_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 F. Padovan04124682012-03-08 01:25:00 -03005281 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08005282}
5283
Johan Hedberg272d90d2012-02-09 15:26:12 +02005284int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005285 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08005286{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005287 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03005288 status,
5289 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08005290}
5291
Johan Hedberg92a25252012-09-06 18:39:26 +03005292int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
5293 u8 link_type, u8 addr_type, u32 passkey,
5294 u8 entered)
5295{
5296 struct mgmt_ev_passkey_notify ev;
5297
5298 BT_DBG("%s", hdev->name);
5299
5300 bacpy(&ev.addr.bdaddr, bdaddr);
5301 ev.addr.type = link_to_bdaddr(link_type, addr_type);
5302 ev.passkey = __cpu_to_le32(passkey);
5303 ev.entered = entered;
5304
5305 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
5306}
5307
Marcel Holtmanne5460992013-10-15 14:26:23 -07005308void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5309 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03005310{
5311 struct mgmt_ev_auth_failed ev;
5312
Johan Hedbergbab73cb2012-02-09 16:07:29 +02005313 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005314 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02005315 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03005316
Marcel Holtmanne5460992013-10-15 14:26:23 -07005317 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03005318}
Johan Hedbergb312b1612011-03-16 14:29:37 +02005319
Marcel Holtmann464996a2013-10-15 14:26:24 -07005320void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005321{
5322 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07005323 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005324
5325 if (status) {
5326 u8 mgmt_err = mgmt_status(status);
5327 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005328 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07005329 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005330 }
5331
Marcel Holtmann464996a2013-10-15 14:26:24 -07005332 if (test_bit(HCI_AUTH, &hdev->flags))
5333 changed = !test_and_set_bit(HCI_LINK_SECURITY,
5334 &hdev->dev_flags);
5335 else
5336 changed = test_and_clear_bit(HCI_LINK_SECURITY,
5337 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02005338
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005339 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005340 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005341
Johan Hedberg47990ea2012-02-22 11:58:37 +02005342 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07005343 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005344
5345 if (match.sk)
5346 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005347}
5348
Johan Hedberg890ea892013-03-15 17:06:52 -05005349static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02005350{
Johan Hedberg890ea892013-03-15 17:06:52 -05005351 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02005352 struct hci_cp_write_eir cp;
5353
Johan Hedberg976eb202012-10-24 21:12:01 +03005354 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05005355 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02005356
Johan Hedbergc80da272012-02-22 15:38:48 +02005357 memset(hdev->eir, 0, sizeof(hdev->eir));
5358
Johan Hedbergcacaf522012-02-21 00:52:42 +02005359 memset(&cp, 0, sizeof(cp));
5360
Johan Hedberg890ea892013-03-15 17:06:52 -05005361 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02005362}
5363
Marcel Holtmann3e248562013-10-15 14:26:25 -07005364void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005365{
5366 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05005367 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005368 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005369
5370 if (status) {
5371 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005372
5373 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005374 &hdev->dev_flags)) {
5375 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07005376 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005377 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005378
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005379 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
5380 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07005381 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005382 }
5383
5384 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005385 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005386 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005387 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
5388 if (!changed)
5389 changed = test_and_clear_bit(HCI_HS_ENABLED,
5390 &hdev->dev_flags);
5391 else
5392 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005393 }
5394
5395 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
5396
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005397 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07005398 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005399
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005400 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005401 sock_put(match.sk);
5402
Johan Hedberg890ea892013-03-15 17:06:52 -05005403 hci_req_init(&req, hdev);
5404
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005405 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05005406 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005407 else
Johan Hedberg890ea892013-03-15 17:06:52 -05005408 clear_eir(&req);
5409
5410 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005411}
5412
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005413void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
5414{
5415 struct cmd_lookup match = { NULL, hdev };
5416 bool changed = false;
5417
5418 if (status) {
5419 u8 mgmt_err = mgmt_status(status);
5420
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005421 if (enable) {
5422 if (test_and_clear_bit(HCI_SC_ENABLED,
5423 &hdev->dev_flags))
5424 new_settings(hdev, NULL);
5425 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
5426 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005427
5428 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5429 cmd_status_rsp, &mgmt_err);
5430 return;
5431 }
5432
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005433 if (enable) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005434 changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005435 } else {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005436 changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005437 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
5438 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005439
5440 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5441 settings_rsp, &match);
5442
5443 if (changed)
5444 new_settings(hdev, match.sk);
5445
5446 if (match.sk)
5447 sock_put(match.sk);
5448}
5449
Johan Hedberg92da6092013-03-15 17:06:55 -05005450static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02005451{
5452 struct cmd_lookup *match = data;
5453
Johan Hedberg90e70452012-02-23 23:09:40 +02005454 if (match->sk == NULL) {
5455 match->sk = cmd->sk;
5456 sock_hold(match->sk);
5457 }
Johan Hedberg90e70452012-02-23 23:09:40 +02005458}
5459
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005460void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
5461 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005462{
Johan Hedberg90e70452012-02-23 23:09:40 +02005463 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005464
Johan Hedberg92da6092013-03-15 17:06:55 -05005465 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
5466 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
5467 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02005468
5469 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005470 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
5471 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02005472
5473 if (match.sk)
5474 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005475}
5476
Marcel Holtmann7667da32013-10-15 14:26:27 -07005477void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02005478{
Johan Hedbergb312b1612011-03-16 14:29:37 +02005479 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05005480 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005481
Johan Hedberg13928972013-03-15 17:07:00 -05005482 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07005483 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005484
5485 memset(&ev, 0, sizeof(ev));
5486 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005487 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005488
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005489 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05005490 if (!cmd) {
5491 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02005492
Johan Hedberg13928972013-03-15 17:07:00 -05005493 /* If this is a HCI command related to powering on the
5494 * HCI dev don't send any mgmt signals.
5495 */
5496 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07005497 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005498 }
5499
Marcel Holtmann7667da32013-10-15 14:26:27 -07005500 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
5501 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005502}
Szymon Jancc35938b2011-03-22 13:12:21 +01005503
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005504void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
5505 u8 *randomizer192, u8 *hash256,
5506 u8 *randomizer256, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01005507{
5508 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01005509
Johan Hedberg744cf192011-11-08 20:40:14 +02005510 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01005511
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005512 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01005513 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005514 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01005515
5516 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005517 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
5518 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01005519 } else {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005520 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
5521 hash256 && randomizer256) {
5522 struct mgmt_rp_read_local_oob_ext_data rp;
Szymon Jancc35938b2011-03-22 13:12:21 +01005523
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005524 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
5525 memcpy(rp.randomizer192, randomizer192,
5526 sizeof(rp.randomizer192));
Szymon Jancc35938b2011-03-22 13:12:21 +01005527
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005528 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
5529 memcpy(rp.randomizer256, randomizer256,
5530 sizeof(rp.randomizer256));
5531
5532 cmd_complete(cmd->sk, hdev->id,
5533 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5534 &rp, sizeof(rp));
5535 } else {
5536 struct mgmt_rp_read_local_oob_data rp;
5537
5538 memcpy(rp.hash, hash192, sizeof(rp.hash));
5539 memcpy(rp.randomizer, randomizer192,
5540 sizeof(rp.randomizer));
5541
5542 cmd_complete(cmd->sk, hdev->id,
5543 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5544 &rp, sizeof(rp));
5545 }
Szymon Jancc35938b2011-03-22 13:12:21 +01005546 }
5547
5548 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01005549}
Johan Hedberge17acd42011-03-30 23:57:16 +03005550
Marcel Holtmann901801b2013-10-06 23:55:51 -07005551void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5552 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
5553 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03005554{
Johan Hedberge319d2e2012-01-15 19:51:59 +02005555 char buf[512];
5556 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg5cedbb82014-02-18 21:41:37 +02005557 struct smp_irk *irk;
Johan Hedberg1dc06092012-01-15 21:01:23 +02005558 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03005559
Andre Guedes12602d02013-04-30 15:29:40 -03005560 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005561 return;
Andre Guedes12602d02013-04-30 15:29:40 -03005562
Johan Hedberg1dc06092012-01-15 21:01:23 +02005563 /* Leave 5 bytes for a potential CoD field */
5564 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005565 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03005566
Johan Hedberg1dc06092012-01-15 21:01:23 +02005567 memset(buf, 0, sizeof(buf));
5568
Johan Hedberg5cedbb82014-02-18 21:41:37 +02005569 irk = hci_get_irk(hdev, bdaddr, addr_type);
5570 if (irk) {
5571 bacpy(&ev->addr.bdaddr, &irk->bdaddr);
5572 ev->addr.type = link_to_bdaddr(link_type, irk->addr_type);
5573 } else {
5574 bacpy(&ev->addr.bdaddr, bdaddr);
5575 ev->addr.type = link_to_bdaddr(link_type, addr_type);
5576 }
5577
Johan Hedberge319d2e2012-01-15 19:51:59 +02005578 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02005579 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305580 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02005581 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305582 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03005583
Johan Hedberg1dc06092012-01-15 21:01:23 +02005584 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02005585 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03005586
Johan Hedberg1dc06092012-01-15 21:01:23 +02005587 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
5588 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005589 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005590
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005591 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005592 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03005593
Marcel Holtmann901801b2013-10-06 23:55:51 -07005594 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03005595}
Johan Hedberga88a9652011-03-30 13:18:12 +03005596
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005597void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5598 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03005599{
Johan Hedbergb644ba32012-01-17 21:48:47 +02005600 struct mgmt_ev_device_found *ev;
5601 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
5602 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03005603
Johan Hedbergb644ba32012-01-17 21:48:47 +02005604 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03005605
Johan Hedbergb644ba32012-01-17 21:48:47 +02005606 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03005607
Johan Hedbergb644ba32012-01-17 21:48:47 +02005608 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005609 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005610 ev->rssi = rssi;
5611
5612 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005613 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005614
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005615 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005616
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005617 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03005618}
Johan Hedberg314b2382011-04-27 10:29:57 -04005619
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005620void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04005621{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005622 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02005623 struct pending_cmd *cmd;
5624
Andre Guedes343fb142011-11-22 17:14:19 -03005625 BT_DBG("%s discovering %u", hdev->name, discovering);
5626
Johan Hedberg164a6e72011-11-01 17:06:44 +02005627 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005628 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005629 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005630 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005631
5632 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02005633 u8 type = hdev->discovery.type;
5634
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005635 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
5636 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02005637 mgmt_pending_remove(cmd);
5638 }
5639
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005640 memset(&ev, 0, sizeof(ev));
5641 ev.type = hdev->discovery.type;
5642 ev.discovering = discovering;
5643
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005644 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04005645}
Antti Julku5e762442011-08-25 16:48:02 +03005646
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005647int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005648{
5649 struct pending_cmd *cmd;
5650 struct mgmt_ev_device_blocked ev;
5651
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005652 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005653
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005654 bacpy(&ev.addr.bdaddr, bdaddr);
5655 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005656
Johan Hedberg744cf192011-11-08 20:40:14 +02005657 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005658 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005659}
5660
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005661int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005662{
5663 struct pending_cmd *cmd;
5664 struct mgmt_ev_device_unblocked ev;
5665
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005666 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005667
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005668 bacpy(&ev.addr.bdaddr, bdaddr);
5669 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005670
Johan Hedberg744cf192011-11-08 20:40:14 +02005671 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005672 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005673}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005674
5675static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5676{
5677 BT_DBG("%s status %u", hdev->name, status);
5678
5679 /* Clear the advertising mgmt setting if we failed to re-enable it */
5680 if (status) {
5681 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005682 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005683 }
5684}
5685
5686void mgmt_reenable_advertising(struct hci_dev *hdev)
5687{
5688 struct hci_request req;
5689
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005690 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005691 return;
5692
5693 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5694 return;
5695
5696 hci_req_init(&req, hdev);
5697 enable_advertising(&req);
5698
5699 /* If this fails we have no option but to let user space know
5700 * that we've disabled advertising.
5701 */
5702 if (hci_req_run(&req, adv_enable_complete) < 0) {
5703 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005704 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005705 }
5706}