blob: 91ffecd1727e932cedab42a861fe3e6f899d7529 [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,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020083};
84
85static const u16 mgmt_events[] = {
86 MGMT_EV_CONTROLLER_ERROR,
87 MGMT_EV_INDEX_ADDED,
88 MGMT_EV_INDEX_REMOVED,
89 MGMT_EV_NEW_SETTINGS,
90 MGMT_EV_CLASS_OF_DEV_CHANGED,
91 MGMT_EV_LOCAL_NAME_CHANGED,
92 MGMT_EV_NEW_LINK_KEY,
93 MGMT_EV_NEW_LONG_TERM_KEY,
94 MGMT_EV_DEVICE_CONNECTED,
95 MGMT_EV_DEVICE_DISCONNECTED,
96 MGMT_EV_CONNECT_FAILED,
97 MGMT_EV_PIN_CODE_REQUEST,
98 MGMT_EV_USER_CONFIRM_REQUEST,
99 MGMT_EV_USER_PASSKEY_REQUEST,
100 MGMT_EV_AUTH_FAILED,
101 MGMT_EV_DEVICE_FOUND,
102 MGMT_EV_DISCOVERING,
103 MGMT_EV_DEVICE_BLOCKED,
104 MGMT_EV_DEVICE_UNBLOCKED,
105 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300106 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200107};
108
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800109#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200110
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200111#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
112 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
113
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200114struct pending_cmd {
115 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200116 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200117 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100118 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200119 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300120 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200121};
122
Johan Hedbergca69b792011-11-11 18:10:00 +0200123/* HCI to MGMT error code conversion table */
124static u8 mgmt_status_table[] = {
125 MGMT_STATUS_SUCCESS,
126 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
127 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
128 MGMT_STATUS_FAILED, /* Hardware Failure */
129 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
130 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200131 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200132 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
133 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
134 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
135 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
136 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
137 MGMT_STATUS_BUSY, /* Command Disallowed */
138 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
139 MGMT_STATUS_REJECTED, /* Rejected Security */
140 MGMT_STATUS_REJECTED, /* Rejected Personal */
141 MGMT_STATUS_TIMEOUT, /* Host Timeout */
142 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
143 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
144 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
145 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
146 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
147 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
148 MGMT_STATUS_BUSY, /* Repeated Attempts */
149 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
150 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
151 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
152 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
153 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
154 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
155 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
156 MGMT_STATUS_FAILED, /* Unspecified Error */
157 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
158 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
159 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
160 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
161 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
162 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
163 MGMT_STATUS_FAILED, /* Unit Link Key Used */
164 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
165 MGMT_STATUS_TIMEOUT, /* Instant Passed */
166 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
167 MGMT_STATUS_FAILED, /* Transaction Collision */
168 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
169 MGMT_STATUS_REJECTED, /* QoS Rejected */
170 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
171 MGMT_STATUS_REJECTED, /* Insufficient Security */
172 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
173 MGMT_STATUS_BUSY, /* Role Switch Pending */
174 MGMT_STATUS_FAILED, /* Slot Violation */
175 MGMT_STATUS_FAILED, /* Role Switch Failed */
176 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
177 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
178 MGMT_STATUS_BUSY, /* Host Busy Pairing */
179 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
180 MGMT_STATUS_BUSY, /* Controller Busy */
181 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
182 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
183 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
184 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
185 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
186};
187
188static u8 mgmt_status(u8 hci_status)
189{
190 if (hci_status < ARRAY_SIZE(mgmt_status_table))
191 return mgmt_status_table[hci_status];
192
193 return MGMT_STATUS_FAILED;
194}
195
Szymon Janc4e51eae2011-02-25 19:05:48 +0100196static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200197{
198 struct sk_buff *skb;
199 struct mgmt_hdr *hdr;
200 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300201 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200202
Szymon Janc34eb5252011-02-28 14:10:08 +0100203 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200204
Andre Guedes790eff42012-06-07 19:05:46 -0300205 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200206 if (!skb)
207 return -ENOMEM;
208
209 hdr = (void *) skb_put(skb, sizeof(*hdr));
210
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530211 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100212 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200213 hdr->len = cpu_to_le16(sizeof(*ev));
214
215 ev = (void *) skb_put(skb, sizeof(*ev));
216 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200217 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200218
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300219 err = sock_queue_rcv_skb(sk, skb);
220 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200221 kfree_skb(skb);
222
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300223 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200224}
225
Johan Hedbergaee9b212012-02-18 15:07:59 +0200226static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300227 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200228{
229 struct sk_buff *skb;
230 struct mgmt_hdr *hdr;
231 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300232 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200233
234 BT_DBG("sock %p", sk);
235
Andre Guedes790eff42012-06-07 19:05:46 -0300236 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200237 if (!skb)
238 return -ENOMEM;
239
240 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200241
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530242 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100243 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200244 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200247 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200248 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100249
250 if (rp)
251 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200252
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300253 err = sock_queue_rcv_skb(sk, skb);
254 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200255 kfree_skb(skb);
256
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100257 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200258}
259
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300260static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
261 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200262{
263 struct mgmt_rp_read_version rp;
264
265 BT_DBG("sock %p", sk);
266
267 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200268 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200269
Johan Hedbergaee9b212012-02-18 15:07:59 +0200270 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300271 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200272}
273
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300274static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
275 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200276{
277 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200278 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
279 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200280 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200281 size_t rp_size;
282 int i, err;
283
284 BT_DBG("sock %p", sk);
285
286 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
287
288 rp = kmalloc(rp_size, GFP_KERNEL);
289 if (!rp)
290 return -ENOMEM;
291
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200292 rp->num_commands = __constant_cpu_to_le16(num_commands);
293 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200294
295 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
296 put_unaligned_le16(mgmt_commands[i], opcode);
297
298 for (i = 0; i < num_events; i++, opcode++)
299 put_unaligned_le16(mgmt_events[i], opcode);
300
Johan Hedbergaee9b212012-02-18 15:07:59 +0200301 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300302 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200303 kfree(rp);
304
305 return err;
306}
307
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300308static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
309 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200310{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200311 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200312 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200313 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200314 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300315 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316
317 BT_DBG("sock %p", sk);
318
319 read_lock(&hci_dev_list_lock);
320
321 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300322 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700323 if (d->dev_type == HCI_BREDR)
324 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200325 }
326
Johan Hedberga38528f2011-01-22 06:46:43 +0200327 rp_len = sizeof(*rp) + (2 * count);
328 rp = kmalloc(rp_len, GFP_ATOMIC);
329 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100330 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200331 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100332 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200333
Johan Hedberg476e44c2012-10-19 20:10:46 +0300334 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200335 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200336 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200337 continue;
338
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700339 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
340 continue;
341
Marcel Holtmann1514b892013-10-06 08:25:01 -0700342 if (d->dev_type == HCI_BREDR) {
343 rp->index[count++] = cpu_to_le16(d->id);
344 BT_DBG("Added hci%u", d->id);
345 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200346 }
347
Johan Hedberg476e44c2012-10-19 20:10:46 +0300348 rp->num_controllers = cpu_to_le16(count);
349 rp_len = sizeof(*rp) + (2 * count);
350
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200351 read_unlock(&hci_dev_list_lock);
352
Johan Hedbergaee9b212012-02-18 15:07:59 +0200353 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300354 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200355
Johan Hedberga38528f2011-01-22 06:46:43 +0200356 kfree(rp);
357
358 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200359}
360
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200361static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200362{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200363 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200364
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_PAIRABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800367 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg03811012010-12-08 00:21:06 +0200368
Andre Guedesed3fa312012-07-24 15:03:46 -0300369 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300370 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500371 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
372 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300373 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200374 settings |= MGMT_SETTING_BREDR;
375 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700376
377 if (lmp_ssp_capable(hdev)) {
378 settings |= MGMT_SETTING_SSP;
379 settings |= MGMT_SETTING_HS;
380 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800381
Marcel Holtmann5afeac12014-01-10 02:07:27 -0800382 if (lmp_sc_capable(hdev) ||
383 test_bit(HCI_FORCE_SC, &hdev->dev_flags))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800384 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700385 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100386
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300387 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200388 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300389 settings |= MGMT_SETTING_ADVERTISING;
390 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200391
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200392 return settings;
393}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200394
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200395static u32 get_current_settings(struct hci_dev *hdev)
396{
397 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200398
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200399 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100400 settings |= MGMT_SETTING_POWERED;
401
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200402 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403 settings |= MGMT_SETTING_CONNECTABLE;
404
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500405 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
406 settings |= MGMT_SETTING_FAST_CONNECTABLE;
407
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200408 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200409 settings |= MGMT_SETTING_DISCOVERABLE;
410
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200411 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200412 settings |= MGMT_SETTING_PAIRABLE;
413
Johan Hedberg56f87902013-10-02 13:43:13 +0300414 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_BREDR;
416
Johan Hedberg06199cf2012-02-22 16:37:11 +0200417 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200418 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200419
Johan Hedberg47990ea2012-02-22 11:58:37 +0200420 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200421 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200422
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200423 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200424 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200425
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200426 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
427 settings |= MGMT_SETTING_HS;
428
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200429 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300430 settings |= MGMT_SETTING_ADVERTISING;
431
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800432 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
433 settings |= MGMT_SETTING_SECURE_CONN;
434
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800435 if (test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags))
436 settings |= MGMT_SETTING_DEBUG_KEYS;
437
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200438 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200439}
440
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300441#define PNP_INFO_SVCLASS_ID 0x1200
442
Johan Hedberg213202e2013-01-27 00:31:33 +0200443static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
444{
445 u8 *ptr = data, *uuids_start = NULL;
446 struct bt_uuid *uuid;
447
448 if (len < 4)
449 return ptr;
450
451 list_for_each_entry(uuid, &hdev->uuids, list) {
452 u16 uuid16;
453
454 if (uuid->size != 16)
455 continue;
456
457 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
458 if (uuid16 < 0x1100)
459 continue;
460
461 if (uuid16 == PNP_INFO_SVCLASS_ID)
462 continue;
463
464 if (!uuids_start) {
465 uuids_start = ptr;
466 uuids_start[0] = 1;
467 uuids_start[1] = EIR_UUID16_ALL;
468 ptr += 2;
469 }
470
471 /* Stop if not enough space to put next UUID */
472 if ((ptr - data) + sizeof(u16) > len) {
473 uuids_start[1] = EIR_UUID16_SOME;
474 break;
475 }
476
477 *ptr++ = (uuid16 & 0x00ff);
478 *ptr++ = (uuid16 & 0xff00) >> 8;
479 uuids_start[0] += sizeof(uuid16);
480 }
481
482 return ptr;
483}
484
Johan Hedbergcdf19632013-01-27 00:31:34 +0200485static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
486{
487 u8 *ptr = data, *uuids_start = NULL;
488 struct bt_uuid *uuid;
489
490 if (len < 6)
491 return ptr;
492
493 list_for_each_entry(uuid, &hdev->uuids, list) {
494 if (uuid->size != 32)
495 continue;
496
497 if (!uuids_start) {
498 uuids_start = ptr;
499 uuids_start[0] = 1;
500 uuids_start[1] = EIR_UUID32_ALL;
501 ptr += 2;
502 }
503
504 /* Stop if not enough space to put next UUID */
505 if ((ptr - data) + sizeof(u32) > len) {
506 uuids_start[1] = EIR_UUID32_SOME;
507 break;
508 }
509
510 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
511 ptr += sizeof(u32);
512 uuids_start[0] += sizeof(u32);
513 }
514
515 return ptr;
516}
517
Johan Hedbergc00d5752013-01-27 00:31:35 +0200518static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
519{
520 u8 *ptr = data, *uuids_start = NULL;
521 struct bt_uuid *uuid;
522
523 if (len < 18)
524 return ptr;
525
526 list_for_each_entry(uuid, &hdev->uuids, list) {
527 if (uuid->size != 128)
528 continue;
529
530 if (!uuids_start) {
531 uuids_start = ptr;
532 uuids_start[0] = 1;
533 uuids_start[1] = EIR_UUID128_ALL;
534 ptr += 2;
535 }
536
537 /* Stop if not enough space to put next UUID */
538 if ((ptr - data) + 16 > len) {
539 uuids_start[1] = EIR_UUID128_SOME;
540 break;
541 }
542
543 memcpy(ptr, uuid->uuid, 16);
544 ptr += 16;
545 uuids_start[0] += 16;
546 }
547
548 return ptr;
549}
550
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300551static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
552{
553 struct pending_cmd *cmd;
554
555 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
556 if (cmd->opcode == opcode)
557 return cmd;
558 }
559
560 return NULL;
561}
562
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700563static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
564{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700565 u8 ad_len = 0;
566 size_t name_len;
567
568 name_len = strlen(hdev->dev_name);
569 if (name_len > 0) {
570 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
571
572 if (name_len > max_len) {
573 name_len = max_len;
574 ptr[1] = EIR_NAME_SHORT;
575 } else
576 ptr[1] = EIR_NAME_COMPLETE;
577
578 ptr[0] = name_len + 1;
579
580 memcpy(ptr + 2, hdev->dev_name, name_len);
581
582 ad_len += (name_len + 2);
583 ptr += (name_len + 2);
584 }
585
586 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700587}
588
589static void update_scan_rsp_data(struct hci_request *req)
590{
591 struct hci_dev *hdev = req->hdev;
592 struct hci_cp_le_set_scan_rsp_data cp;
593 u8 len;
594
Johan Hedberg7751ef12013-10-19 23:38:15 +0300595 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700596 return;
597
598 memset(&cp, 0, sizeof(cp));
599
600 len = create_scan_rsp_data(hdev, cp.data);
601
Johan Hedbergeb438b52013-10-16 15:31:07 +0300602 if (hdev->scan_rsp_data_len == len &&
603 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700604 return;
605
Johan Hedbergeb438b52013-10-16 15:31:07 +0300606 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
607 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700608
609 cp.length = len;
610
611 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
612}
613
Johan Hedberg9a43e252013-10-20 19:00:07 +0300614static u8 get_adv_discov_flags(struct hci_dev *hdev)
615{
616 struct pending_cmd *cmd;
617
618 /* If there's a pending mgmt command the flags will not yet have
619 * their final values, so check for this first.
620 */
621 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
622 if (cmd) {
623 struct mgmt_mode *cp = cmd->param;
624 if (cp->val == 0x01)
625 return LE_AD_GENERAL;
626 else if (cp->val == 0x02)
627 return LE_AD_LIMITED;
628 } else {
629 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
630 return LE_AD_LIMITED;
631 else if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
632 return LE_AD_GENERAL;
633 }
634
635 return 0;
636}
637
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700638static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700639{
640 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700641
Johan Hedberg9a43e252013-10-20 19:00:07 +0300642 flags |= get_adv_discov_flags(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700643
Johan Hedberge8340042014-01-30 11:16:50 -0800644 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700645 flags |= LE_AD_NO_BREDR;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700646
647 if (flags) {
648 BT_DBG("adv flags 0x%02x", flags);
649
650 ptr[0] = 2;
651 ptr[1] = EIR_FLAGS;
652 ptr[2] = flags;
653
654 ad_len += 3;
655 ptr += 3;
656 }
657
658 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
659 ptr[0] = 2;
660 ptr[1] = EIR_TX_POWER;
661 ptr[2] = (u8) hdev->adv_tx_power;
662
663 ad_len += 3;
664 ptr += 3;
665 }
666
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700667 return ad_len;
668}
669
Marcel Holtmann5947f4b2013-10-16 00:16:50 -0700670static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700671{
672 struct hci_dev *hdev = req->hdev;
673 struct hci_cp_le_set_adv_data cp;
674 u8 len;
675
Johan Hedberg10994ce2013-10-19 23:38:16 +0300676 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700677 return;
678
679 memset(&cp, 0, sizeof(cp));
680
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700681 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700682
683 if (hdev->adv_data_len == len &&
684 memcmp(cp.data, hdev->adv_data, len) == 0)
685 return;
686
687 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
688 hdev->adv_data_len = len;
689
690 cp.length = len;
691
692 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
693}
694
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300695static void create_eir(struct hci_dev *hdev, u8 *data)
696{
697 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300698 size_t name_len;
699
700 name_len = strlen(hdev->dev_name);
701
702 if (name_len > 0) {
703 /* EIR Data type */
704 if (name_len > 48) {
705 name_len = 48;
706 ptr[1] = EIR_NAME_SHORT;
707 } else
708 ptr[1] = EIR_NAME_COMPLETE;
709
710 /* EIR Data length */
711 ptr[0] = name_len + 1;
712
713 memcpy(ptr + 2, hdev->dev_name, name_len);
714
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300715 ptr += (name_len + 2);
716 }
717
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100718 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700719 ptr[0] = 2;
720 ptr[1] = EIR_TX_POWER;
721 ptr[2] = (u8) hdev->inq_tx_power;
722
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700723 ptr += 3;
724 }
725
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700726 if (hdev->devid_source > 0) {
727 ptr[0] = 9;
728 ptr[1] = EIR_DEVICE_ID;
729
730 put_unaligned_le16(hdev->devid_source, ptr + 2);
731 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
732 put_unaligned_le16(hdev->devid_product, ptr + 6);
733 put_unaligned_le16(hdev->devid_version, ptr + 8);
734
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700735 ptr += 10;
736 }
737
Johan Hedberg213202e2013-01-27 00:31:33 +0200738 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200739 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200740 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300741}
742
Johan Hedberg890ea892013-03-15 17:06:52 -0500743static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300744{
Johan Hedberg890ea892013-03-15 17:06:52 -0500745 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300746 struct hci_cp_write_eir cp;
747
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200748 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500749 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200750
Johan Hedberg976eb202012-10-24 21:12:01 +0300751 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500752 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300753
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200754 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500755 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300756
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200757 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500758 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300759
760 memset(&cp, 0, sizeof(cp));
761
762 create_eir(hdev, cp.data);
763
764 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500765 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300766
767 memcpy(hdev->eir, cp.data, sizeof(cp.data));
768
Johan Hedberg890ea892013-03-15 17:06:52 -0500769 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300770}
771
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200772static u8 get_service_classes(struct hci_dev *hdev)
773{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300774 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200775 u8 val = 0;
776
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300777 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200778 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200779
780 return val;
781}
782
Johan Hedberg890ea892013-03-15 17:06:52 -0500783static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200784{
Johan Hedberg890ea892013-03-15 17:06:52 -0500785 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200786 u8 cod[3];
787
788 BT_DBG("%s", hdev->name);
789
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200790 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500791 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200792
Johan Hedbergf87ea1d2013-10-19 23:38:17 +0300793 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
794 return;
795
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200796 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500797 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200798
799 cod[0] = hdev->minor_class;
800 cod[1] = hdev->major_class;
801 cod[2] = get_service_classes(hdev);
802
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700803 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
804 cod[1] |= 0x20;
805
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200806 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500807 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200808
Johan Hedberg890ea892013-03-15 17:06:52 -0500809 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200810}
811
Johan Hedberg7d785252011-12-15 00:47:39 +0200812static void service_cache_off(struct work_struct *work)
813{
814 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300815 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500816 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200817
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200818 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200819 return;
820
Johan Hedberg890ea892013-03-15 17:06:52 -0500821 hci_req_init(&req, hdev);
822
Johan Hedberg7d785252011-12-15 00:47:39 +0200823 hci_dev_lock(hdev);
824
Johan Hedberg890ea892013-03-15 17:06:52 -0500825 update_eir(&req);
826 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200827
828 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500829
830 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200831}
832
Johan Hedberg6a919082012-02-28 06:17:26 +0200833static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200834{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200835 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200836 return;
837
Johan Hedberg4f87da82012-03-02 19:55:56 +0200838 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200839
Johan Hedberg4f87da82012-03-02 19:55:56 +0200840 /* Non-mgmt controlled devices get this bit set
841 * implicitly so that pairing works for them, however
842 * for mgmt we require user-space to explicitly enable
843 * it
844 */
845 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200846}
847
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200848static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300849 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200850{
851 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200852
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200853 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200854
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300855 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200856
Johan Hedberg03811012010-12-08 00:21:06 +0200857 memset(&rp, 0, sizeof(rp));
858
Johan Hedberg03811012010-12-08 00:21:06 +0200859 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200860
861 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200862 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200863
864 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
865 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
866
867 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200868
869 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200870 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200871
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300872 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200873
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200874 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300875 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200876}
877
878static void mgmt_pending_free(struct pending_cmd *cmd)
879{
880 sock_put(cmd->sk);
881 kfree(cmd->param);
882 kfree(cmd);
883}
884
885static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300886 struct hci_dev *hdev, void *data,
887 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200888{
889 struct pending_cmd *cmd;
890
Andre Guedes12b94562012-06-07 19:05:45 -0300891 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200892 if (!cmd)
893 return NULL;
894
895 cmd->opcode = opcode;
896 cmd->index = hdev->id;
897
Andre Guedes12b94562012-06-07 19:05:45 -0300898 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200899 if (!cmd->param) {
900 kfree(cmd);
901 return NULL;
902 }
903
904 if (data)
905 memcpy(cmd->param, data, len);
906
907 cmd->sk = sk;
908 sock_hold(sk);
909
910 list_add(&cmd->list, &hdev->mgmt_pending);
911
912 return cmd;
913}
914
915static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300916 void (*cb)(struct pending_cmd *cmd,
917 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300918 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200919{
Andre Guedesa3d09352013-02-01 11:21:30 -0300920 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200921
Andre Guedesa3d09352013-02-01 11:21:30 -0300922 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200923 if (opcode > 0 && cmd->opcode != opcode)
924 continue;
925
926 cb(cmd, data);
927 }
928}
929
Johan Hedberg03811012010-12-08 00:21:06 +0200930static void mgmt_pending_remove(struct pending_cmd *cmd)
931{
932 list_del(&cmd->list);
933 mgmt_pending_free(cmd);
934}
935
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200936static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200937{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200938 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200939
Johan Hedbergaee9b212012-02-18 15:07:59 +0200940 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300941 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200942}
943
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200944static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300945 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200946{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300947 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200948 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200949 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200950
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200951 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200952
Johan Hedberga7e80f22013-01-09 16:05:19 +0200953 if (cp->val != 0x00 && cp->val != 0x01)
954 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
955 MGMT_STATUS_INVALID_PARAMS);
956
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300957 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200958
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300959 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
960 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
961 MGMT_STATUS_BUSY);
962 goto failed;
963 }
964
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100965 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
966 cancel_delayed_work(&hdev->power_off);
967
968 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200969 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
970 data, len);
971 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100972 goto failed;
973 }
974 }
975
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200976 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200977 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200978 goto failed;
979 }
980
Johan Hedberg03811012010-12-08 00:21:06 +0200981 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
982 if (!cmd) {
983 err = -ENOMEM;
984 goto failed;
985 }
986
987 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200988 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200989 else
Johan Hedberg19202572013-01-14 22:33:51 +0200990 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200991
992 err = 0;
993
994failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300995 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200996 return err;
997}
998
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300999static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
1000 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001001{
1002 struct sk_buff *skb;
1003 struct mgmt_hdr *hdr;
1004
Andre Guedes790eff42012-06-07 19:05:46 -03001005 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001006 if (!skb)
1007 return -ENOMEM;
1008
1009 hdr = (void *) skb_put(skb, sizeof(*hdr));
1010 hdr->opcode = cpu_to_le16(event);
1011 if (hdev)
1012 hdr->index = cpu_to_le16(hdev->id);
1013 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05301014 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001015 hdr->len = cpu_to_le16(data_len);
1016
1017 if (data)
1018 memcpy(skb_put(skb, data_len), data, data_len);
1019
Marcel Holtmann97e0bde2012-02-22 13:49:28 +01001020 /* Time stamp */
1021 __net_timestamp(skb);
1022
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001023 hci_send_to_control(skb, skip_sk);
1024 kfree_skb(skb);
1025
1026 return 0;
1027}
1028
1029static int new_settings(struct hci_dev *hdev, struct sock *skip)
1030{
1031 __le32 ev;
1032
1033 ev = cpu_to_le32(get_current_settings(hdev));
1034
1035 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1036}
1037
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001038struct cmd_lookup {
1039 struct sock *sk;
1040 struct hci_dev *hdev;
1041 u8 mgmt_status;
1042};
1043
1044static void settings_rsp(struct pending_cmd *cmd, void *data)
1045{
1046 struct cmd_lookup *match = data;
1047
1048 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1049
1050 list_del(&cmd->list);
1051
1052 if (match->sk == NULL) {
1053 match->sk = cmd->sk;
1054 sock_hold(match->sk);
1055 }
1056
1057 mgmt_pending_free(cmd);
1058}
1059
1060static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1061{
1062 u8 *status = data;
1063
1064 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1065 mgmt_pending_remove(cmd);
1066}
1067
Johan Hedberge6fe7982013-10-02 15:45:22 +03001068static u8 mgmt_bredr_support(struct hci_dev *hdev)
1069{
1070 if (!lmp_bredr_capable(hdev))
1071 return MGMT_STATUS_NOT_SUPPORTED;
1072 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1073 return MGMT_STATUS_REJECTED;
1074 else
1075 return MGMT_STATUS_SUCCESS;
1076}
1077
1078static u8 mgmt_le_support(struct hci_dev *hdev)
1079{
1080 if (!lmp_le_capable(hdev))
1081 return MGMT_STATUS_NOT_SUPPORTED;
1082 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1083 return MGMT_STATUS_REJECTED;
1084 else
1085 return MGMT_STATUS_SUCCESS;
1086}
1087
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001088static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1089{
1090 struct pending_cmd *cmd;
1091 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001092 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001093 bool changed;
1094
1095 BT_DBG("status 0x%02x", status);
1096
1097 hci_dev_lock(hdev);
1098
1099 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1100 if (!cmd)
1101 goto unlock;
1102
1103 if (status) {
1104 u8 mgmt_err = mgmt_status(status);
1105 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001106 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001107 goto remove_cmd;
1108 }
1109
1110 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001111 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001112 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1113 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001114
1115 if (hdev->discov_timeout > 0) {
1116 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1117 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1118 to);
1119 }
1120 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001121 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1122 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001123 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001124
1125 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1126
1127 if (changed)
1128 new_settings(hdev, cmd->sk);
1129
Marcel Holtmann970ba522013-10-15 06:33:57 -07001130 /* When the discoverable mode gets changed, make sure
1131 * that class of device has the limited discoverable
1132 * bit correctly set.
1133 */
1134 hci_req_init(&req, hdev);
1135 update_class(&req);
1136 hci_req_run(&req, NULL);
1137
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001138remove_cmd:
1139 mgmt_pending_remove(cmd);
1140
1141unlock:
1142 hci_dev_unlock(hdev);
1143}
1144
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001145static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001146 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001147{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001148 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001149 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001150 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001151 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001152 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001153 int err;
1154
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001155 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001156
Johan Hedberg9a43e252013-10-20 19:00:07 +03001157 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1158 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001159 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberg9a43e252013-10-20 19:00:07 +03001160 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001161
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001162 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga7e80f22013-01-09 16:05:19 +02001163 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1164 MGMT_STATUS_INVALID_PARAMS);
1165
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001166 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001167
1168 /* Disabling discoverable requires that no timeout is set,
1169 * and enabling limited discoverable requires a timeout.
1170 */
1171 if ((cp->val == 0x00 && timeout > 0) ||
1172 (cp->val == 0x02 && timeout == 0))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001173 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001174 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001175
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001176 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001177
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001178 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001179 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001180 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001181 goto failed;
1182 }
1183
1184 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001185 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001186 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001187 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001188 goto failed;
1189 }
1190
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001191 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001192 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001193 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001194 goto failed;
1195 }
1196
1197 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001198 bool changed = false;
1199
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001200 /* Setting limited discoverable when powered off is
1201 * not a valid operation since it requires a timeout
1202 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1203 */
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001204 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1205 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1206 changed = true;
1207 }
1208
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001209 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001210 if (err < 0)
1211 goto failed;
1212
1213 if (changed)
1214 err = new_settings(hdev, sk);
1215
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001216 goto failed;
1217 }
1218
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001219 /* If the current mode is the same, then just update the timeout
1220 * value with the new value. And if only the timeout gets updated,
1221 * then no need for any HCI transactions.
1222 */
1223 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) &&
1224 (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE,
1225 &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001226 cancel_delayed_work(&hdev->discov_off);
1227 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001228
Marcel Holtmann36261542013-10-15 08:28:51 -07001229 if (cp->val && hdev->discov_timeout > 0) {
1230 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001231 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001232 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001233 }
1234
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001235 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001236 goto failed;
1237 }
1238
1239 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1240 if (!cmd) {
1241 err = -ENOMEM;
1242 goto failed;
1243 }
1244
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001245 /* Cancel any potential discoverable timeout that might be
1246 * still active and store new timeout value. The arming of
1247 * the timeout happens in the complete handler.
1248 */
1249 cancel_delayed_work(&hdev->discov_off);
1250 hdev->discov_timeout = timeout;
1251
Johan Hedbergb456f872013-10-19 23:38:22 +03001252 /* Limited discoverable mode */
1253 if (cp->val == 0x02)
1254 set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1255 else
1256 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1257
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001258 hci_req_init(&req, hdev);
1259
Johan Hedberg9a43e252013-10-20 19:00:07 +03001260 /* The procedure for LE-only controllers is much simpler - just
1261 * update the advertising data.
1262 */
1263 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1264 goto update_ad;
1265
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001266 scan = SCAN_PAGE;
1267
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001268 if (cp->val) {
1269 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001270
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001271 if (cp->val == 0x02) {
1272 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001273 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001274 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1275 hci_cp.iac_lap[1] = 0x8b;
1276 hci_cp.iac_lap[2] = 0x9e;
1277 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1278 hci_cp.iac_lap[4] = 0x8b;
1279 hci_cp.iac_lap[5] = 0x9e;
1280 } else {
1281 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001282 hci_cp.num_iac = 1;
1283 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1284 hci_cp.iac_lap[1] = 0x8b;
1285 hci_cp.iac_lap[2] = 0x9e;
1286 }
1287
1288 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1289 (hci_cp.num_iac * 3) + 1, &hci_cp);
1290
1291 scan |= SCAN_INQUIRY;
1292 } else {
1293 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1294 }
1295
1296 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001297
Johan Hedberg9a43e252013-10-20 19:00:07 +03001298update_ad:
1299 update_adv_data(&req);
1300
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001301 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001302 if (err < 0)
1303 mgmt_pending_remove(cmd);
1304
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001305failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001306 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001307 return err;
1308}
1309
Johan Hedberg406d7802013-03-15 17:07:09 -05001310static void write_fast_connectable(struct hci_request *req, bool enable)
1311{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001312 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001313 struct hci_cp_write_page_scan_activity acp;
1314 u8 type;
1315
Johan Hedberg547003b2013-10-21 16:51:53 +03001316 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1317 return;
1318
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001319 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1320 return;
1321
Johan Hedberg406d7802013-03-15 17:07:09 -05001322 if (enable) {
1323 type = PAGE_SCAN_TYPE_INTERLACED;
1324
1325 /* 160 msec page scan interval */
1326 acp.interval = __constant_cpu_to_le16(0x0100);
1327 } else {
1328 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1329
1330 /* default 1.28 sec page scan */
1331 acp.interval = __constant_cpu_to_le16(0x0800);
1332 }
1333
1334 acp.window = __constant_cpu_to_le16(0x0012);
1335
Johan Hedbergbd98b992013-03-15 17:07:13 -05001336 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1337 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1338 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1339 sizeof(acp), &acp);
1340
1341 if (hdev->page_scan_type != type)
1342 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001343}
1344
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001345static u8 get_adv_type(struct hci_dev *hdev)
1346{
1347 struct pending_cmd *cmd;
1348 bool connectable;
1349
1350 /* If there's a pending mgmt command the flag will not yet have
1351 * it's final value, so check for this first.
1352 */
1353 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1354 if (cmd) {
1355 struct mgmt_mode *cp = cmd->param;
1356 connectable = !!cp->val;
1357 } else {
1358 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1359 }
1360
1361 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1362}
1363
Johan Hedberg95c66e72013-10-14 16:20:06 +03001364static void enable_advertising(struct hci_request *req)
1365{
1366 struct hci_dev *hdev = req->hdev;
1367 struct hci_cp_le_set_adv_param cp;
1368 u8 enable = 0x01;
1369
1370 memset(&cp, 0, sizeof(cp));
1371 cp.min_interval = __constant_cpu_to_le16(0x0800);
1372 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001373 cp.type = get_adv_type(hdev);
Marcel Holtmann79830f62013-10-18 16:38:09 -07001374 cp.own_address_type = hdev->own_addr_type;
Johan Hedberg95c66e72013-10-14 16:20:06 +03001375 cp.channel_map = 0x07;
1376
1377 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1378
1379 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1380}
1381
1382static void disable_advertising(struct hci_request *req)
1383{
1384 u8 enable = 0x00;
1385
1386 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1387}
1388
Johan Hedberg2b76f452013-03-15 17:07:04 -05001389static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1390{
1391 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001392 struct mgmt_mode *cp;
1393 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001394
1395 BT_DBG("status 0x%02x", status);
1396
1397 hci_dev_lock(hdev);
1398
1399 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1400 if (!cmd)
1401 goto unlock;
1402
Johan Hedberg37438c12013-10-14 16:20:05 +03001403 if (status) {
1404 u8 mgmt_err = mgmt_status(status);
1405 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1406 goto remove_cmd;
1407 }
1408
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001409 cp = cmd->param;
1410 if (cp->val)
1411 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1412 else
1413 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1414
Johan Hedberg2b76f452013-03-15 17:07:04 -05001415 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1416
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001417 if (changed)
1418 new_settings(hdev, cmd->sk);
1419
Johan Hedberg37438c12013-10-14 16:20:05 +03001420remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001421 mgmt_pending_remove(cmd);
1422
1423unlock:
1424 hci_dev_unlock(hdev);
1425}
1426
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001427static int set_connectable_update_settings(struct hci_dev *hdev,
1428 struct sock *sk, u8 val)
1429{
1430 bool changed = false;
1431 int err;
1432
1433 if (!!val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1434 changed = true;
1435
1436 if (val) {
1437 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1438 } else {
1439 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1440 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1441 }
1442
1443 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1444 if (err < 0)
1445 return err;
1446
1447 if (changed)
1448 return new_settings(hdev, sk);
1449
1450 return 0;
1451}
1452
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001453static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001454 u16 len)
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001455{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001456 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001457 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001458 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001459 u8 scan;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001460 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001461
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001462 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001463
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001464 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1465 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001466 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001467 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001468
Johan Hedberga7e80f22013-01-09 16:05:19 +02001469 if (cp->val != 0x00 && cp->val != 0x01)
1470 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1471 MGMT_STATUS_INVALID_PARAMS);
1472
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001473 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001474
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001475 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001476 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001477 goto failed;
1478 }
1479
1480 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001481 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001482 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001483 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001484 goto failed;
1485 }
1486
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001487 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1488 if (!cmd) {
1489 err = -ENOMEM;
1490 goto failed;
1491 }
1492
Johan Hedberg2b76f452013-03-15 17:07:04 -05001493 hci_req_init(&req, hdev);
1494
Johan Hedberg9a43e252013-10-20 19:00:07 +03001495 /* If BR/EDR is not enabled and we disable advertising as a
1496 * by-product of disabling connectable, we need to update the
1497 * advertising flags.
1498 */
1499 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
1500 if (!cp->val) {
1501 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1502 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1503 }
1504 update_adv_data(&req);
1505 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001506 if (cp->val) {
1507 scan = SCAN_PAGE;
1508 } else {
1509 scan = 0;
1510
1511 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001512 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001513 cancel_delayed_work(&hdev->discov_off);
1514 }
1515
1516 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1517 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001518
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001519 /* If we're going from non-connectable to connectable or
1520 * vice-versa when fast connectable is enabled ensure that fast
1521 * connectable gets disabled. write_fast_connectable won't do
1522 * anything if the page scan parameters are already what they
1523 * should be.
1524 */
1525 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001526 write_fast_connectable(&req, false);
1527
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001528 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1529 hci_conn_num(hdev, LE_LINK) == 0) {
1530 disable_advertising(&req);
1531 enable_advertising(&req);
1532 }
1533
Johan Hedberg2b76f452013-03-15 17:07:04 -05001534 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001535 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001536 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001537 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03001538 err = set_connectable_update_settings(hdev, sk,
1539 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03001540 goto failed;
1541 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001542
1543failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001544 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001545 return err;
1546}
1547
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001548static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001549 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001550{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001551 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001552 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001553 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001554
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001555 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001556
Johan Hedberga7e80f22013-01-09 16:05:19 +02001557 if (cp->val != 0x00 && cp->val != 0x01)
1558 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1559 MGMT_STATUS_INVALID_PARAMS);
1560
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001561 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001562
1563 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001564 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001565 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001566 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001567
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001568 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001569 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001570 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001571
Marcel Holtmann55594352013-10-06 16:11:57 -07001572 if (changed)
1573 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001574
Marcel Holtmann55594352013-10-06 16:11:57 -07001575unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001576 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001577 return err;
1578}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001579
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001580static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1581 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001582{
1583 struct mgmt_mode *cp = data;
1584 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001585 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001586 int err;
1587
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001588 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001589
Johan Hedberge6fe7982013-10-02 15:45:22 +03001590 status = mgmt_bredr_support(hdev);
1591 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001592 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001593 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001594
Johan Hedberga7e80f22013-01-09 16:05:19 +02001595 if (cp->val != 0x00 && cp->val != 0x01)
1596 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1597 MGMT_STATUS_INVALID_PARAMS);
1598
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001599 hci_dev_lock(hdev);
1600
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001601 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001602 bool changed = false;
1603
1604 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001605 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001606 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1607 changed = true;
1608 }
1609
1610 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1611 if (err < 0)
1612 goto failed;
1613
1614 if (changed)
1615 err = new_settings(hdev, sk);
1616
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001617 goto failed;
1618 }
1619
1620 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001621 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001622 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001623 goto failed;
1624 }
1625
1626 val = !!cp->val;
1627
1628 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1629 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1630 goto failed;
1631 }
1632
1633 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1634 if (!cmd) {
1635 err = -ENOMEM;
1636 goto failed;
1637 }
1638
1639 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1640 if (err < 0) {
1641 mgmt_pending_remove(cmd);
1642 goto failed;
1643 }
1644
1645failed:
1646 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001647 return err;
1648}
1649
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001650static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001651{
1652 struct mgmt_mode *cp = data;
1653 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001654 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001655 int err;
1656
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001657 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001658
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001659 status = mgmt_bredr_support(hdev);
1660 if (status)
1661 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1662
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001663 if (!lmp_ssp_capable(hdev))
1664 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1665 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001666
Johan Hedberga7e80f22013-01-09 16:05:19 +02001667 if (cp->val != 0x00 && cp->val != 0x01)
1668 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1669 MGMT_STATUS_INVALID_PARAMS);
1670
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001671 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001672
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001673 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001674 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001675
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001676 if (cp->val) {
1677 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1678 &hdev->dev_flags);
1679 } else {
1680 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1681 &hdev->dev_flags);
1682 if (!changed)
1683 changed = test_and_clear_bit(HCI_HS_ENABLED,
1684 &hdev->dev_flags);
1685 else
1686 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001687 }
1688
1689 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1690 if (err < 0)
1691 goto failed;
1692
1693 if (changed)
1694 err = new_settings(hdev, sk);
1695
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001696 goto failed;
1697 }
1698
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001699 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1700 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001701 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1702 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001703 goto failed;
1704 }
1705
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001706 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001707 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1708 goto failed;
1709 }
1710
1711 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1712 if (!cmd) {
1713 err = -ENOMEM;
1714 goto failed;
1715 }
1716
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001717 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001718 if (err < 0) {
1719 mgmt_pending_remove(cmd);
1720 goto failed;
1721 }
1722
1723failed:
1724 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001725 return err;
1726}
1727
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001728static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001729{
1730 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001731 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001732 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001733 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001734
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001735 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001736
Johan Hedberge6fe7982013-10-02 15:45:22 +03001737 status = mgmt_bredr_support(hdev);
1738 if (status)
1739 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001740
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001741 if (!lmp_ssp_capable(hdev))
1742 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1743 MGMT_STATUS_NOT_SUPPORTED);
1744
1745 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1746 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1747 MGMT_STATUS_REJECTED);
1748
Johan Hedberga7e80f22013-01-09 16:05:19 +02001749 if (cp->val != 0x00 && cp->val != 0x01)
1750 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1751 MGMT_STATUS_INVALID_PARAMS);
1752
Marcel Holtmannee392692013-10-01 22:59:23 -07001753 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001754
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001755 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001756 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001757 } else {
1758 if (hdev_is_powered(hdev)) {
1759 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1760 MGMT_STATUS_REJECTED);
1761 goto unlock;
1762 }
1763
Marcel Holtmannee392692013-10-01 22:59:23 -07001764 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001765 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001766
1767 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1768 if (err < 0)
1769 goto unlock;
1770
1771 if (changed)
1772 err = new_settings(hdev, sk);
1773
1774unlock:
1775 hci_dev_unlock(hdev);
1776 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001777}
1778
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001779static void le_enable_complete(struct hci_dev *hdev, u8 status)
1780{
1781 struct cmd_lookup match = { NULL, hdev };
1782
1783 if (status) {
1784 u8 mgmt_err = mgmt_status(status);
1785
1786 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1787 &mgmt_err);
1788 return;
1789 }
1790
1791 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1792
1793 new_settings(hdev, match.sk);
1794
1795 if (match.sk)
1796 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001797
1798 /* Make sure the controller has a good default for
1799 * advertising data. Restrict the update to when LE
1800 * has actually been enabled. During power on, the
1801 * update in powered_update_hci will take care of it.
1802 */
1803 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1804 struct hci_request req;
1805
1806 hci_dev_lock(hdev);
1807
1808 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001809 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07001810 update_scan_rsp_data(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001811 hci_req_run(&req, NULL);
1812
1813 hci_dev_unlock(hdev);
1814 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001815}
1816
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001817static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001818{
1819 struct mgmt_mode *cp = data;
1820 struct hci_cp_write_le_host_supported hci_cp;
1821 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001822 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001823 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001824 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001825
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001826 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001827
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001828 if (!lmp_le_capable(hdev))
1829 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1830 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001831
Johan Hedberga7e80f22013-01-09 16:05:19 +02001832 if (cp->val != 0x00 && cp->val != 0x01)
1833 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1834 MGMT_STATUS_INVALID_PARAMS);
1835
Johan Hedbergc73eee92013-04-19 18:35:21 +03001836 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001837 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001838 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1839 MGMT_STATUS_REJECTED);
1840
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001841 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001842
1843 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001844 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001845
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001846 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001847 bool changed = false;
1848
1849 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1850 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1851 changed = true;
1852 }
1853
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001854 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1855 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001856 changed = true;
1857 }
1858
Johan Hedberg06199cf2012-02-22 16:37:11 +02001859 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1860 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001861 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001862
1863 if (changed)
1864 err = new_settings(hdev, sk);
1865
Johan Hedberg1de028c2012-02-29 19:55:35 -08001866 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001867 }
1868
Johan Hedberg4375f102013-09-25 13:26:10 +03001869 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1870 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001871 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001872 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001873 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001874 }
1875
1876 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1877 if (!cmd) {
1878 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001879 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001880 }
1881
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001882 hci_req_init(&req, hdev);
1883
Johan Hedberg06199cf2012-02-22 16:37:11 +02001884 memset(&hci_cp, 0, sizeof(hci_cp));
1885
1886 if (val) {
1887 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001888 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001889 } else {
1890 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1891 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001892 }
1893
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001894 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1895 &hci_cp);
1896
1897 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301898 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001899 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001900
Johan Hedberg1de028c2012-02-29 19:55:35 -08001901unlock:
1902 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001903 return err;
1904}
1905
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001906/* This is a helper function to test for pending mgmt commands that can
1907 * cause CoD or EIR HCI commands. We can only allow one such pending
1908 * mgmt command at a time since otherwise we cannot easily track what
1909 * the current values are, will be, and based on that calculate if a new
1910 * HCI command needs to be sent and if yes with what value.
1911 */
1912static bool pending_eir_or_class(struct hci_dev *hdev)
1913{
1914 struct pending_cmd *cmd;
1915
1916 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1917 switch (cmd->opcode) {
1918 case MGMT_OP_ADD_UUID:
1919 case MGMT_OP_REMOVE_UUID:
1920 case MGMT_OP_SET_DEV_CLASS:
1921 case MGMT_OP_SET_POWERED:
1922 return true;
1923 }
1924 }
1925
1926 return false;
1927}
1928
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001929static const u8 bluetooth_base_uuid[] = {
1930 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1931 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1932};
1933
1934static u8 get_uuid_size(const u8 *uuid)
1935{
1936 u32 val;
1937
1938 if (memcmp(uuid, bluetooth_base_uuid, 12))
1939 return 128;
1940
1941 val = get_unaligned_le32(&uuid[12]);
1942 if (val > 0xffff)
1943 return 32;
1944
1945 return 16;
1946}
1947
Johan Hedberg92da6092013-03-15 17:06:55 -05001948static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1949{
1950 struct pending_cmd *cmd;
1951
1952 hci_dev_lock(hdev);
1953
1954 cmd = mgmt_pending_find(mgmt_op, hdev);
1955 if (!cmd)
1956 goto unlock;
1957
1958 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1959 hdev->dev_class, 3);
1960
1961 mgmt_pending_remove(cmd);
1962
1963unlock:
1964 hci_dev_unlock(hdev);
1965}
1966
1967static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1968{
1969 BT_DBG("status 0x%02x", status);
1970
1971 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1972}
1973
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001974static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001975{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001976 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001977 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001978 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001979 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001980 int err;
1981
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001982 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001983
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001984 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001985
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001986 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001987 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001988 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001989 goto failed;
1990 }
1991
Andre Guedes92c4c202012-06-07 19:05:44 -03001992 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001993 if (!uuid) {
1994 err = -ENOMEM;
1995 goto failed;
1996 }
1997
1998 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001999 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002000 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002001
Johan Hedbergde66aa62013-01-27 00:31:27 +02002002 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002003
Johan Hedberg890ea892013-03-15 17:06:52 -05002004 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002005
Johan Hedberg890ea892013-03-15 17:06:52 -05002006 update_class(&req);
2007 update_eir(&req);
2008
Johan Hedberg92da6092013-03-15 17:06:55 -05002009 err = hci_req_run(&req, add_uuid_complete);
2010 if (err < 0) {
2011 if (err != -ENODATA)
2012 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002013
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002014 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002015 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002016 goto failed;
2017 }
2018
2019 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002020 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002021 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002022 goto failed;
2023 }
2024
2025 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002026
2027failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002028 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002029 return err;
2030}
2031
Johan Hedberg24b78d02012-02-23 23:24:30 +02002032static bool enable_service_cache(struct hci_dev *hdev)
2033{
2034 if (!hdev_is_powered(hdev))
2035 return false;
2036
2037 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002038 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2039 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002040 return true;
2041 }
2042
2043 return false;
2044}
2045
Johan Hedberg92da6092013-03-15 17:06:55 -05002046static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
2047{
2048 BT_DBG("status 0x%02x", status);
2049
2050 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2051}
2052
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002053static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002054 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002055{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002056 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002057 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002058 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002059 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 -05002060 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002061 int err, found;
2062
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002063 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002064
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002065 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002066
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002067 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002068 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002069 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002070 goto unlock;
2071 }
2072
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002073 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
2074 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002075
Johan Hedberg24b78d02012-02-23 23:24:30 +02002076 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002077 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002078 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002079 goto unlock;
2080 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002081
Johan Hedberg9246a862012-02-23 21:33:16 +02002082 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002083 }
2084
2085 found = 0;
2086
Johan Hedberg056341c2013-01-27 00:31:30 +02002087 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002088 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2089 continue;
2090
2091 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002092 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002093 found++;
2094 }
2095
2096 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002097 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002098 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002099 goto unlock;
2100 }
2101
Johan Hedberg9246a862012-02-23 21:33:16 +02002102update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002103 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002104
Johan Hedberg890ea892013-03-15 17:06:52 -05002105 update_class(&req);
2106 update_eir(&req);
2107
Johan Hedberg92da6092013-03-15 17:06:55 -05002108 err = hci_req_run(&req, remove_uuid_complete);
2109 if (err < 0) {
2110 if (err != -ENODATA)
2111 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002112
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002113 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002114 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002115 goto unlock;
2116 }
2117
2118 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002119 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002120 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002121 goto unlock;
2122 }
2123
2124 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002125
2126unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002127 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002128 return err;
2129}
2130
Johan Hedberg92da6092013-03-15 17:06:55 -05002131static void set_class_complete(struct hci_dev *hdev, u8 status)
2132{
2133 BT_DBG("status 0x%02x", status);
2134
2135 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2136}
2137
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002138static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002139 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002140{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002141 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002142 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002143 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002144 int err;
2145
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002146 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002147
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002148 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002149 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2150 MGMT_STATUS_NOT_SUPPORTED);
2151
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002152 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002153
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002154 if (pending_eir_or_class(hdev)) {
2155 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2156 MGMT_STATUS_BUSY);
2157 goto unlock;
2158 }
2159
2160 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2161 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2162 MGMT_STATUS_INVALID_PARAMS);
2163 goto unlock;
2164 }
2165
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002166 hdev->major_class = cp->major;
2167 hdev->minor_class = cp->minor;
2168
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002169 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002170 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002171 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002172 goto unlock;
2173 }
2174
Johan Hedberg890ea892013-03-15 17:06:52 -05002175 hci_req_init(&req, hdev);
2176
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002177 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002178 hci_dev_unlock(hdev);
2179 cancel_delayed_work_sync(&hdev->service_cache);
2180 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002181 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002182 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002183
Johan Hedberg890ea892013-03-15 17:06:52 -05002184 update_class(&req);
2185
Johan Hedberg92da6092013-03-15 17:06:55 -05002186 err = hci_req_run(&req, set_class_complete);
2187 if (err < 0) {
2188 if (err != -ENODATA)
2189 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002190
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002191 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002192 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002193 goto unlock;
2194 }
2195
2196 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002197 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002198 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002199 goto unlock;
2200 }
2201
2202 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002203
Johan Hedbergb5235a62012-02-21 14:32:24 +02002204unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002205 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002206 return err;
2207}
2208
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002209static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002210 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002211{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002212 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002213 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002214 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002215 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002216
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002217 BT_DBG("request for %s", hdev->name);
2218
2219 if (!lmp_bredr_capable(hdev))
2220 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2221 MGMT_STATUS_NOT_SUPPORTED);
2222
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002223 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002224
Johan Hedberg86742e12011-11-07 23:13:38 +02002225 expected_len = sizeof(*cp) + key_count *
2226 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002227 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002228 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002229 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002230 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002231 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002232 }
2233
Johan Hedberg4ae143012013-01-20 14:27:13 +02002234 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2235 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2236 MGMT_STATUS_INVALID_PARAMS);
2237
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002238 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002239 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002240
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002241 for (i = 0; i < key_count; i++) {
2242 struct mgmt_link_key_info *key = &cp->keys[i];
2243
Marcel Holtmann8e991132014-01-10 02:07:25 -08002244 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002245 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2246 MGMT_STATUS_INVALID_PARAMS);
2247 }
2248
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002249 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002250
2251 hci_link_keys_clear(hdev);
2252
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002253 if (cp->debug_keys)
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002254 changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002255 else
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002256 changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
2257
2258 if (changed)
2259 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002260
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002261 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002262 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002263
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002264 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002265 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002266 }
2267
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002268 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002269
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002270 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002271
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002272 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002273}
2274
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002275static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002276 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002277{
2278 struct mgmt_ev_device_unpaired ev;
2279
2280 bacpy(&ev.addr.bdaddr, bdaddr);
2281 ev.addr.type = addr_type;
2282
2283 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002284 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002285}
2286
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002287static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002288 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002289{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002290 struct mgmt_cp_unpair_device *cp = data;
2291 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002292 struct hci_cp_disconnect dc;
2293 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002294 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002295 int err;
2296
Johan Hedberga8a1d192011-11-10 15:54:38 +02002297 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002298 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2299 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002300
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002301 if (!bdaddr_type_is_valid(cp->addr.type))
2302 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2303 MGMT_STATUS_INVALID_PARAMS,
2304 &rp, sizeof(rp));
2305
Johan Hedberg118da702013-01-20 14:27:20 +02002306 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2307 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2308 MGMT_STATUS_INVALID_PARAMS,
2309 &rp, sizeof(rp));
2310
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002311 hci_dev_lock(hdev);
2312
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002313 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002314 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002315 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002316 goto unlock;
2317 }
2318
Andre Guedes591f47f2012-04-24 21:02:49 -03002319 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02002320 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
2321 else
2322 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002323
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002324 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002325 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002326 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002327 goto unlock;
2328 }
2329
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002330 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002331 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002332 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002333 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002334 else
2335 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002336 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002337 } else {
2338 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002339 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002340
Johan Hedberga8a1d192011-11-10 15:54:38 +02002341 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002342 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002343 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002344 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002345 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002346 }
2347
Johan Hedberg124f6e32012-02-09 13:50:12 +02002348 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002349 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002350 if (!cmd) {
2351 err = -ENOMEM;
2352 goto unlock;
2353 }
2354
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002355 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002356 dc.reason = 0x13; /* Remote User Terminated Connection */
2357 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2358 if (err < 0)
2359 mgmt_pending_remove(cmd);
2360
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002361unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002362 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002363 return err;
2364}
2365
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002366static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002367 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002368{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002369 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002370 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002371 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002372 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002373 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002374 int err;
2375
2376 BT_DBG("");
2377
Johan Hedberg06a63b12013-01-20 14:27:21 +02002378 memset(&rp, 0, sizeof(rp));
2379 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2380 rp.addr.type = cp->addr.type;
2381
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002382 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002383 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2384 MGMT_STATUS_INVALID_PARAMS,
2385 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002386
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002387 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002388
2389 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002390 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2391 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002392 goto failed;
2393 }
2394
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002395 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002396 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2397 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002398 goto failed;
2399 }
2400
Andre Guedes591f47f2012-04-24 21:02:49 -03002401 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002402 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2403 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002404 else
2405 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002406
Vishal Agarwalf9607272012-06-13 05:32:43 +05302407 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002408 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2409 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002410 goto failed;
2411 }
2412
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002413 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002414 if (!cmd) {
2415 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002416 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002417 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002418
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002419 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002420 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002421
2422 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2423 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002424 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002425
2426failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002427 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002428 return err;
2429}
2430
Andre Guedes57c14772012-04-24 21:02:50 -03002431static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002432{
2433 switch (link_type) {
2434 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002435 switch (addr_type) {
2436 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002437 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002438
Johan Hedberg48264f02011-11-09 13:58:58 +02002439 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002440 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002441 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002442 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002443
Johan Hedberg4c659c32011-11-07 23:13:39 +02002444 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002445 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002446 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002447 }
2448}
2449
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002450static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2451 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002452{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002453 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002454 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002455 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002456 int err;
2457 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002458
2459 BT_DBG("");
2460
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002461 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002462
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002463 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002464 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002465 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002466 goto unlock;
2467 }
2468
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002469 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002470 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2471 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002472 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002473 }
2474
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002475 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002476 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002477 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002478 err = -ENOMEM;
2479 goto unlock;
2480 }
2481
Johan Hedberg2784eb42011-01-21 13:56:35 +02002482 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002483 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002484 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2485 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002486 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002487 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002488 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002489 continue;
2490 i++;
2491 }
2492
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002493 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002494
Johan Hedberg4c659c32011-11-07 23:13:39 +02002495 /* Recalculate length in case of filtered SCO connections, etc */
2496 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002497
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002498 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002499 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002500
Johan Hedberga38528f2011-01-22 06:46:43 +02002501 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002502
2503unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002504 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002505 return err;
2506}
2507
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002508static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002509 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002510{
2511 struct pending_cmd *cmd;
2512 int err;
2513
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002514 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002515 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002516 if (!cmd)
2517 return -ENOMEM;
2518
Johan Hedbergd8457692012-02-17 14:24:57 +02002519 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002520 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002521 if (err < 0)
2522 mgmt_pending_remove(cmd);
2523
2524 return err;
2525}
2526
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002527static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002528 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002529{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002530 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002531 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002532 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002533 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002534 int err;
2535
2536 BT_DBG("");
2537
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002538 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002539
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002540 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002541 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002542 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002543 goto failed;
2544 }
2545
Johan Hedbergd8457692012-02-17 14:24:57 +02002546 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002547 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002548 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002549 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002550 goto failed;
2551 }
2552
2553 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002554 struct mgmt_cp_pin_code_neg_reply ncp;
2555
2556 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002557
2558 BT_ERR("PIN code is not 16 bytes long");
2559
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002560 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002561 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002562 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002563 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002564
2565 goto failed;
2566 }
2567
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002568 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002569 if (!cmd) {
2570 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002571 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002572 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002573
Johan Hedbergd8457692012-02-17 14:24:57 +02002574 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002575 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002576 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002577
2578 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2579 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002580 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002581
2582failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002583 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002584 return err;
2585}
2586
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002587static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2588 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002589{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002590 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002591
2592 BT_DBG("");
2593
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002594 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002595
2596 hdev->io_capability = cp->io_capability;
2597
2598 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002599 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002600
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002601 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002602
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002603 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2604 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002605}
2606
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002607static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002608{
2609 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002610 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002611
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002612 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002613 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2614 continue;
2615
Johan Hedberge9a416b2011-02-19 12:05:56 -03002616 if (cmd->user_data != conn)
2617 continue;
2618
2619 return cmd;
2620 }
2621
2622 return NULL;
2623}
2624
2625static void pairing_complete(struct pending_cmd *cmd, u8 status)
2626{
2627 struct mgmt_rp_pair_device rp;
2628 struct hci_conn *conn = cmd->user_data;
2629
Johan Hedbergba4e5642011-11-11 00:07:34 +02002630 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002631 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002632
Johan Hedbergaee9b212012-02-18 15:07:59 +02002633 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002634 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002635
2636 /* So we don't get further callbacks for this connection */
2637 conn->connect_cfm_cb = NULL;
2638 conn->security_cfm_cb = NULL;
2639 conn->disconn_cfm_cb = NULL;
2640
David Herrmann76a68ba2013-04-06 20:28:37 +02002641 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002642
Johan Hedberga664b5b2011-02-19 12:06:02 -03002643 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002644}
2645
2646static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2647{
2648 struct pending_cmd *cmd;
2649
2650 BT_DBG("status %u", status);
2651
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002652 cmd = find_pairing(conn);
2653 if (!cmd)
2654 BT_DBG("Unable to find a pending command");
2655 else
Johan Hedberge2113262012-02-18 15:20:03 +02002656 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002657}
2658
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302659static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2660{
2661 struct pending_cmd *cmd;
2662
2663 BT_DBG("status %u", status);
2664
2665 if (!status)
2666 return;
2667
2668 cmd = find_pairing(conn);
2669 if (!cmd)
2670 BT_DBG("Unable to find a pending command");
2671 else
2672 pairing_complete(cmd, mgmt_status(status));
2673}
2674
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002675static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002676 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002677{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002678 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002679 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002680 struct pending_cmd *cmd;
2681 u8 sec_level, auth_type;
2682 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002683 int err;
2684
2685 BT_DBG("");
2686
Szymon Jancf950a30e2013-01-18 12:48:07 +01002687 memset(&rp, 0, sizeof(rp));
2688 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2689 rp.addr.type = cp->addr.type;
2690
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002691 if (!bdaddr_type_is_valid(cp->addr.type))
2692 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2693 MGMT_STATUS_INVALID_PARAMS,
2694 &rp, sizeof(rp));
2695
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002696 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002697
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002698 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002699 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2700 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002701 goto unlock;
2702 }
2703
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002704 sec_level = BT_SECURITY_MEDIUM;
2705 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002706 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002707 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002708 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002709
Andre Guedes591f47f2012-04-24 21:02:49 -03002710 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002711 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2712 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002713 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002714 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2715 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002716
Ville Tervo30e76272011-02-22 16:10:53 -03002717 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002718 int status;
2719
2720 if (PTR_ERR(conn) == -EBUSY)
2721 status = MGMT_STATUS_BUSY;
2722 else
2723 status = MGMT_STATUS_CONNECT_FAILED;
2724
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002725 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002726 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002727 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002728 goto unlock;
2729 }
2730
2731 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002732 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002733 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002734 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002735 goto unlock;
2736 }
2737
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002738 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002739 if (!cmd) {
2740 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002741 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002742 goto unlock;
2743 }
2744
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002745 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002746 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002747 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302748 else
2749 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002750
Johan Hedberge9a416b2011-02-19 12:05:56 -03002751 conn->security_cfm_cb = pairing_complete_cb;
2752 conn->disconn_cfm_cb = pairing_complete_cb;
2753 conn->io_capability = cp->io_cap;
2754 cmd->user_data = conn;
2755
2756 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002757 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002758 pairing_complete(cmd, 0);
2759
2760 err = 0;
2761
2762unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002763 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002764 return err;
2765}
2766
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002767static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2768 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002769{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002770 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002771 struct pending_cmd *cmd;
2772 struct hci_conn *conn;
2773 int err;
2774
2775 BT_DBG("");
2776
Johan Hedberg28424702012-02-02 04:02:29 +02002777 hci_dev_lock(hdev);
2778
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002779 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002780 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002781 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002782 goto unlock;
2783 }
2784
Johan Hedberg28424702012-02-02 04:02:29 +02002785 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2786 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002787 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002788 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002789 goto unlock;
2790 }
2791
2792 conn = cmd->user_data;
2793
2794 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002795 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002796 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002797 goto unlock;
2798 }
2799
2800 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2801
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002802 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002803 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002804unlock:
2805 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002806 return err;
2807}
2808
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002809static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002810 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002811 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002812{
Johan Hedberga5c29682011-02-19 12:05:57 -03002813 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002814 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002815 int err;
2816
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002817 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002818
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002819 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002820 err = cmd_complete(sk, hdev->id, mgmt_op,
2821 MGMT_STATUS_NOT_POWERED, addr,
2822 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002823 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002824 }
2825
Johan Hedberg1707c602013-03-15 17:07:15 -05002826 if (addr->type == BDADDR_BREDR)
2827 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002828 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002829 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002830
Johan Hedberg272d90d2012-02-09 15:26:12 +02002831 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002832 err = cmd_complete(sk, hdev->id, mgmt_op,
2833 MGMT_STATUS_NOT_CONNECTED, addr,
2834 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002835 goto done;
2836 }
2837
Johan Hedberg1707c602013-03-15 17:07:15 -05002838 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002839 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002840 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002841
Brian Gix5fe57d92011-12-21 16:12:13 -08002842 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002843 err = cmd_complete(sk, hdev->id, mgmt_op,
2844 MGMT_STATUS_SUCCESS, addr,
2845 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002846 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002847 err = cmd_complete(sk, hdev->id, mgmt_op,
2848 MGMT_STATUS_FAILED, addr,
2849 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002850
Brian Gix47c15e22011-11-16 13:53:14 -08002851 goto done;
2852 }
2853
Johan Hedberg1707c602013-03-15 17:07:15 -05002854 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002855 if (!cmd) {
2856 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002857 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002858 }
2859
Brian Gix0df4c182011-11-16 13:53:13 -08002860 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002861 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2862 struct hci_cp_user_passkey_reply cp;
2863
Johan Hedberg1707c602013-03-15 17:07:15 -05002864 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002865 cp.passkey = passkey;
2866 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2867 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002868 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2869 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002870
Johan Hedberga664b5b2011-02-19 12:06:02 -03002871 if (err < 0)
2872 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002873
Brian Gix0df4c182011-11-16 13:53:13 -08002874done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002875 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002876 return err;
2877}
2878
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302879static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2880 void *data, u16 len)
2881{
2882 struct mgmt_cp_pin_code_neg_reply *cp = data;
2883
2884 BT_DBG("");
2885
Johan Hedberg1707c602013-03-15 17:07:15 -05002886 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302887 MGMT_OP_PIN_CODE_NEG_REPLY,
2888 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2889}
2890
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002891static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2892 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002893{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002894 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002895
2896 BT_DBG("");
2897
2898 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002899 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002900 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002901
Johan Hedberg1707c602013-03-15 17:07:15 -05002902 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002903 MGMT_OP_USER_CONFIRM_REPLY,
2904 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002905}
2906
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002907static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002908 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002909{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002910 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002911
2912 BT_DBG("");
2913
Johan Hedberg1707c602013-03-15 17:07:15 -05002914 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002915 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2916 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002917}
2918
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002919static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2920 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002921{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002922 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002923
2924 BT_DBG("");
2925
Johan Hedberg1707c602013-03-15 17:07:15 -05002926 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002927 MGMT_OP_USER_PASSKEY_REPLY,
2928 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002929}
2930
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002931static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002932 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002933{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002934 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002935
2936 BT_DBG("");
2937
Johan Hedberg1707c602013-03-15 17:07:15 -05002938 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002939 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2940 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002941}
2942
Johan Hedberg13928972013-03-15 17:07:00 -05002943static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002944{
Johan Hedberg13928972013-03-15 17:07:00 -05002945 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002946 struct hci_cp_write_local_name cp;
2947
Johan Hedberg13928972013-03-15 17:07:00 -05002948 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002949
Johan Hedberg890ea892013-03-15 17:06:52 -05002950 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002951}
2952
Johan Hedberg13928972013-03-15 17:07:00 -05002953static void set_name_complete(struct hci_dev *hdev, u8 status)
2954{
2955 struct mgmt_cp_set_local_name *cp;
2956 struct pending_cmd *cmd;
2957
2958 BT_DBG("status 0x%02x", status);
2959
2960 hci_dev_lock(hdev);
2961
2962 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2963 if (!cmd)
2964 goto unlock;
2965
2966 cp = cmd->param;
2967
2968 if (status)
2969 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2970 mgmt_status(status));
2971 else
2972 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2973 cp, sizeof(*cp));
2974
2975 mgmt_pending_remove(cmd);
2976
2977unlock:
2978 hci_dev_unlock(hdev);
2979}
2980
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002981static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002982 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002983{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002984 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002985 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002986 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002987 int err;
2988
2989 BT_DBG("");
2990
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002991 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002992
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002993 /* If the old values are the same as the new ones just return a
2994 * direct command complete event.
2995 */
2996 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2997 !memcmp(hdev->short_name, cp->short_name,
2998 sizeof(hdev->short_name))) {
2999 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3000 data, len);
3001 goto failed;
3002 }
3003
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003004 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003005
Johan Hedbergb5235a62012-02-21 14:32:24 +02003006 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003007 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003008
3009 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003010 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003011 if (err < 0)
3012 goto failed;
3013
3014 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003015 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003016
Johan Hedbergb5235a62012-02-21 14:32:24 +02003017 goto failed;
3018 }
3019
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003020 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003021 if (!cmd) {
3022 err = -ENOMEM;
3023 goto failed;
3024 }
3025
Johan Hedberg13928972013-03-15 17:07:00 -05003026 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3027
Johan Hedberg890ea892013-03-15 17:06:52 -05003028 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003029
3030 if (lmp_bredr_capable(hdev)) {
3031 update_name(&req);
3032 update_eir(&req);
3033 }
3034
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003035 /* The name is stored in the scan response data and so
3036 * no need to udpate the advertising data here.
3037 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003038 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003039 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003040
Johan Hedberg13928972013-03-15 17:07:00 -05003041 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003042 if (err < 0)
3043 mgmt_pending_remove(cmd);
3044
3045failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003046 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003047 return err;
3048}
3049
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003050static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003051 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003052{
Szymon Jancc35938b2011-03-22 13:12:21 +01003053 struct pending_cmd *cmd;
3054 int err;
3055
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003056 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003057
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003058 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003059
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003060 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003061 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003062 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003063 goto unlock;
3064 }
3065
Andre Guedes9a1a1992012-07-24 15:03:48 -03003066 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003067 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003068 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003069 goto unlock;
3070 }
3071
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003072 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003073 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003074 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003075 goto unlock;
3076 }
3077
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003078 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003079 if (!cmd) {
3080 err = -ENOMEM;
3081 goto unlock;
3082 }
3083
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003084 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
3085 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
3086 0, NULL);
3087 else
3088 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3089
Szymon Jancc35938b2011-03-22 13:12:21 +01003090 if (err < 0)
3091 mgmt_pending_remove(cmd);
3092
3093unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003094 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003095 return err;
3096}
3097
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003098static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003099 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003100{
Szymon Janc2763eda2011-03-22 13:12:22 +01003101 int err;
3102
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003103 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003104
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003105 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003106
Marcel Holtmannec109112014-01-10 02:07:30 -08003107 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3108 struct mgmt_cp_add_remote_oob_data *cp = data;
3109 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003110
Marcel Holtmannec109112014-01-10 02:07:30 -08003111 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
3112 cp->hash, cp->randomizer);
3113 if (err < 0)
3114 status = MGMT_STATUS_FAILED;
3115 else
3116 status = MGMT_STATUS_SUCCESS;
3117
3118 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3119 status, &cp->addr, sizeof(cp->addr));
3120 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3121 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
3122 u8 status;
3123
3124 err = hci_add_remote_oob_ext_data(hdev, &cp->addr.bdaddr,
3125 cp->hash192,
3126 cp->randomizer192,
3127 cp->hash256,
3128 cp->randomizer256);
3129 if (err < 0)
3130 status = MGMT_STATUS_FAILED;
3131 else
3132 status = MGMT_STATUS_SUCCESS;
3133
3134 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3135 status, &cp->addr, sizeof(cp->addr));
3136 } else {
3137 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
3138 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3139 MGMT_STATUS_INVALID_PARAMS);
3140 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003141
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003142 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003143 return err;
3144}
3145
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003146static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003147 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003148{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003149 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003150 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003151 int err;
3152
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003153 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003154
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003155 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003156
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003157 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003158 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003159 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003160 else
Szymon Janca6785be2012-12-13 15:11:21 +01003161 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003162
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003163 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003164 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003165
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003166 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003167 return err;
3168}
3169
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003170static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3171{
3172 struct pending_cmd *cmd;
3173 u8 type;
3174 int err;
3175
3176 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3177
3178 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3179 if (!cmd)
3180 return -ENOENT;
3181
3182 type = hdev->discovery.type;
3183
3184 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3185 &type, sizeof(type));
3186 mgmt_pending_remove(cmd);
3187
3188 return err;
3189}
3190
Andre Guedes7c307722013-04-30 15:29:28 -03003191static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3192{
3193 BT_DBG("status %d", status);
3194
3195 if (status) {
3196 hci_dev_lock(hdev);
3197 mgmt_start_discovery_failed(hdev, status);
3198 hci_dev_unlock(hdev);
3199 return;
3200 }
3201
3202 hci_dev_lock(hdev);
3203 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3204 hci_dev_unlock(hdev);
3205
3206 switch (hdev->discovery.type) {
3207 case DISCOV_TYPE_LE:
3208 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003209 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003210 break;
3211
3212 case DISCOV_TYPE_INTERLEAVED:
3213 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003214 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003215 break;
3216
3217 case DISCOV_TYPE_BREDR:
3218 break;
3219
3220 default:
3221 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3222 }
3223}
3224
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003225static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003226 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003227{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003228 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003229 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003230 struct hci_cp_le_set_scan_param param_cp;
3231 struct hci_cp_le_set_scan_enable enable_cp;
3232 struct hci_cp_inquiry inq_cp;
3233 struct hci_request req;
3234 /* General inquiry access code (GIAC) */
3235 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003236 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003237 int err;
3238
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003239 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003240
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003241 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003242
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003243 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003244 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003245 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003246 goto failed;
3247 }
3248
Andre Guedes642be6c2012-03-21 00:03:37 -03003249 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3250 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3251 MGMT_STATUS_BUSY);
3252 goto failed;
3253 }
3254
Johan Hedbergff9ef572012-01-04 14:23:45 +02003255 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003256 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003257 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003258 goto failed;
3259 }
3260
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003261 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003262 if (!cmd) {
3263 err = -ENOMEM;
3264 goto failed;
3265 }
3266
Andre Guedes4aab14e2012-02-17 20:39:36 -03003267 hdev->discovery.type = cp->type;
3268
Andre Guedes7c307722013-04-30 15:29:28 -03003269 hci_req_init(&req, hdev);
3270
Andre Guedes4aab14e2012-02-17 20:39:36 -03003271 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003272 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003273 status = mgmt_bredr_support(hdev);
3274 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003275 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003276 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003277 mgmt_pending_remove(cmd);
3278 goto failed;
3279 }
3280
Andre Guedes7c307722013-04-30 15:29:28 -03003281 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3282 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3283 MGMT_STATUS_BUSY);
3284 mgmt_pending_remove(cmd);
3285 goto failed;
3286 }
3287
3288 hci_inquiry_cache_flush(hdev);
3289
3290 memset(&inq_cp, 0, sizeof(inq_cp));
3291 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003292 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003293 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003294 break;
3295
3296 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003297 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003298 status = mgmt_le_support(hdev);
3299 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003300 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003301 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003302 mgmt_pending_remove(cmd);
3303 goto failed;
3304 }
3305
Andre Guedes7c307722013-04-30 15:29:28 -03003306 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003307 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003308 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3309 MGMT_STATUS_NOT_SUPPORTED);
3310 mgmt_pending_remove(cmd);
3311 goto failed;
3312 }
3313
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003314 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003315 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3316 MGMT_STATUS_REJECTED);
3317 mgmt_pending_remove(cmd);
3318 goto failed;
3319 }
3320
3321 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3322 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3323 MGMT_STATUS_BUSY);
3324 mgmt_pending_remove(cmd);
3325 goto failed;
3326 }
3327
3328 memset(&param_cp, 0, sizeof(param_cp));
3329 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003330 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3331 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmann79830f62013-10-18 16:38:09 -07003332 param_cp.own_address_type = hdev->own_addr_type;
Andre Guedes7c307722013-04-30 15:29:28 -03003333 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3334 &param_cp);
3335
3336 memset(&enable_cp, 0, sizeof(enable_cp));
3337 enable_cp.enable = LE_SCAN_ENABLE;
3338 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3339 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3340 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003341 break;
3342
Andre Guedesf39799f2012-02-17 20:39:35 -03003343 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003344 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3345 MGMT_STATUS_INVALID_PARAMS);
3346 mgmt_pending_remove(cmd);
3347 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003348 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003349
Andre Guedes7c307722013-04-30 15:29:28 -03003350 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003351 if (err < 0)
3352 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003353 else
3354 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003355
3356failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003357 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003358 return err;
3359}
3360
Andre Guedes1183fdc2013-04-30 15:29:35 -03003361static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3362{
3363 struct pending_cmd *cmd;
3364 int err;
3365
3366 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3367 if (!cmd)
3368 return -ENOENT;
3369
3370 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3371 &hdev->discovery.type, sizeof(hdev->discovery.type));
3372 mgmt_pending_remove(cmd);
3373
3374 return err;
3375}
3376
Andre Guedes0e05bba2013-04-30 15:29:33 -03003377static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3378{
3379 BT_DBG("status %d", status);
3380
3381 hci_dev_lock(hdev);
3382
3383 if (status) {
3384 mgmt_stop_discovery_failed(hdev, status);
3385 goto unlock;
3386 }
3387
3388 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3389
3390unlock:
3391 hci_dev_unlock(hdev);
3392}
3393
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003394static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003395 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003396{
Johan Hedbergd9306502012-02-20 23:25:18 +02003397 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003398 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003399 struct hci_cp_remote_name_req_cancel cp;
3400 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003401 struct hci_request req;
3402 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003403 int err;
3404
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003405 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003406
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003407 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003408
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003409 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003410 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003411 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3412 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003413 goto unlock;
3414 }
3415
3416 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003417 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003418 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3419 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003420 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003421 }
3422
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003423 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003424 if (!cmd) {
3425 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003426 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003427 }
3428
Andre Guedes0e05bba2013-04-30 15:29:33 -03003429 hci_req_init(&req, hdev);
3430
Andre Guedese0d9727e2012-03-20 15:15:36 -03003431 switch (hdev->discovery.state) {
3432 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003433 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3434 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3435 } else {
3436 cancel_delayed_work(&hdev->le_scan_disable);
3437
3438 memset(&enable_cp, 0, sizeof(enable_cp));
3439 enable_cp.enable = LE_SCAN_DISABLE;
3440 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3441 sizeof(enable_cp), &enable_cp);
3442 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003443
Andre Guedese0d9727e2012-03-20 15:15:36 -03003444 break;
3445
3446 case DISCOVERY_RESOLVING:
3447 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003448 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003449 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003450 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003451 err = cmd_complete(sk, hdev->id,
3452 MGMT_OP_STOP_DISCOVERY, 0,
3453 &mgmt_cp->type,
3454 sizeof(mgmt_cp->type));
3455 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3456 goto unlock;
3457 }
3458
3459 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003460 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3461 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003462
3463 break;
3464
3465 default:
3466 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003467
3468 mgmt_pending_remove(cmd);
3469 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3470 MGMT_STATUS_FAILED, &mgmt_cp->type,
3471 sizeof(mgmt_cp->type));
3472 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003473 }
3474
Andre Guedes0e05bba2013-04-30 15:29:33 -03003475 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003476 if (err < 0)
3477 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003478 else
3479 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003480
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003481unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003482 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003483 return err;
3484}
3485
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003486static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003487 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003488{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003489 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003490 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003491 int err;
3492
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003493 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003494
Johan Hedberg561aafb2012-01-04 13:31:59 +02003495 hci_dev_lock(hdev);
3496
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003497 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003498 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003499 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003500 goto failed;
3501 }
3502
Johan Hedberga198e7b2012-02-17 14:27:06 +02003503 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003504 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003505 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003506 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003507 goto failed;
3508 }
3509
3510 if (cp->name_known) {
3511 e->name_state = NAME_KNOWN;
3512 list_del(&e->list);
3513 } else {
3514 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02003515 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003516 }
3517
Johan Hedberge3846622013-01-09 15:29:33 +02003518 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3519 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003520
3521failed:
3522 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003523 return err;
3524}
3525
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003526static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003527 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003528{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003529 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003530 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003531 int err;
3532
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003533 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003534
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003535 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003536 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3537 MGMT_STATUS_INVALID_PARAMS,
3538 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003539
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003540 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003541
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003542 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003543 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003544 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003545 else
Szymon Janca6785be2012-12-13 15:11:21 +01003546 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003547
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003548 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003549 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003550
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003551 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003552
3553 return err;
3554}
3555
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003556static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003557 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003558{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003559 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003560 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003561 int err;
3562
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003563 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003564
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003565 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003566 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3567 MGMT_STATUS_INVALID_PARAMS,
3568 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003569
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003570 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003571
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003572 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003573 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003574 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003575 else
Szymon Janca6785be2012-12-13 15:11:21 +01003576 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003577
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003578 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003579 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003580
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003581 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003582
3583 return err;
3584}
3585
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003586static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3587 u16 len)
3588{
3589 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003590 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003591 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003592 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003593
3594 BT_DBG("%s", hdev->name);
3595
Szymon Jancc72d4b82012-03-16 16:02:57 +01003596 source = __le16_to_cpu(cp->source);
3597
3598 if (source > 0x0002)
3599 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3600 MGMT_STATUS_INVALID_PARAMS);
3601
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003602 hci_dev_lock(hdev);
3603
Szymon Jancc72d4b82012-03-16 16:02:57 +01003604 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003605 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3606 hdev->devid_product = __le16_to_cpu(cp->product);
3607 hdev->devid_version = __le16_to_cpu(cp->version);
3608
3609 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3610
Johan Hedberg890ea892013-03-15 17:06:52 -05003611 hci_req_init(&req, hdev);
3612 update_eir(&req);
3613 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003614
3615 hci_dev_unlock(hdev);
3616
3617 return err;
3618}
3619
Johan Hedberg4375f102013-09-25 13:26:10 +03003620static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3621{
3622 struct cmd_lookup match = { NULL, hdev };
3623
3624 if (status) {
3625 u8 mgmt_err = mgmt_status(status);
3626
3627 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3628 cmd_status_rsp, &mgmt_err);
3629 return;
3630 }
3631
3632 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3633 &match);
3634
3635 new_settings(hdev, match.sk);
3636
3637 if (match.sk)
3638 sock_put(match.sk);
3639}
3640
Marcel Holtmann21b51872013-10-10 09:47:53 -07003641static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3642 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003643{
3644 struct mgmt_mode *cp = data;
3645 struct pending_cmd *cmd;
3646 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003647 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003648 int err;
3649
3650 BT_DBG("request for %s", hdev->name);
3651
Johan Hedberge6fe7982013-10-02 15:45:22 +03003652 status = mgmt_le_support(hdev);
3653 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003654 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003655 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003656
3657 if (cp->val != 0x00 && cp->val != 0x01)
3658 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3659 MGMT_STATUS_INVALID_PARAMS);
3660
3661 hci_dev_lock(hdev);
3662
3663 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003664 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003665
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003666 /* The following conditions are ones which mean that we should
3667 * not do any HCI communication but directly send a mgmt
3668 * response to user space (after toggling the flag if
3669 * necessary).
3670 */
3671 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003672 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003673 bool changed = false;
3674
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003675 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3676 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003677 changed = true;
3678 }
3679
3680 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3681 if (err < 0)
3682 goto unlock;
3683
3684 if (changed)
3685 err = new_settings(hdev, sk);
3686
3687 goto unlock;
3688 }
3689
3690 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3691 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3692 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3693 MGMT_STATUS_BUSY);
3694 goto unlock;
3695 }
3696
3697 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3698 if (!cmd) {
3699 err = -ENOMEM;
3700 goto unlock;
3701 }
3702
3703 hci_req_init(&req, hdev);
3704
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003705 if (val)
3706 enable_advertising(&req);
3707 else
3708 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003709
3710 err = hci_req_run(&req, set_advertising_complete);
3711 if (err < 0)
3712 mgmt_pending_remove(cmd);
3713
3714unlock:
3715 hci_dev_unlock(hdev);
3716 return err;
3717}
3718
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003719static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3720 void *data, u16 len)
3721{
3722 struct mgmt_cp_set_static_address *cp = data;
3723 int err;
3724
3725 BT_DBG("%s", hdev->name);
3726
Marcel Holtmann62af4442013-10-02 22:10:32 -07003727 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003728 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003729 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003730
3731 if (hdev_is_powered(hdev))
3732 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3733 MGMT_STATUS_REJECTED);
3734
3735 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3736 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3737 return cmd_status(sk, hdev->id,
3738 MGMT_OP_SET_STATIC_ADDRESS,
3739 MGMT_STATUS_INVALID_PARAMS);
3740
3741 /* Two most significant bits shall be set */
3742 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3743 return cmd_status(sk, hdev->id,
3744 MGMT_OP_SET_STATIC_ADDRESS,
3745 MGMT_STATUS_INVALID_PARAMS);
3746 }
3747
3748 hci_dev_lock(hdev);
3749
3750 bacpy(&hdev->static_addr, &cp->bdaddr);
3751
3752 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3753
3754 hci_dev_unlock(hdev);
3755
3756 return err;
3757}
3758
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003759static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3760 void *data, u16 len)
3761{
3762 struct mgmt_cp_set_scan_params *cp = data;
3763 __u16 interval, window;
3764 int err;
3765
3766 BT_DBG("%s", hdev->name);
3767
3768 if (!lmp_le_capable(hdev))
3769 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3770 MGMT_STATUS_NOT_SUPPORTED);
3771
3772 interval = __le16_to_cpu(cp->interval);
3773
3774 if (interval < 0x0004 || interval > 0x4000)
3775 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3776 MGMT_STATUS_INVALID_PARAMS);
3777
3778 window = __le16_to_cpu(cp->window);
3779
3780 if (window < 0x0004 || window > 0x4000)
3781 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3782 MGMT_STATUS_INVALID_PARAMS);
3783
Marcel Holtmann899e1072013-10-14 09:55:32 -07003784 if (window > interval)
3785 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3786 MGMT_STATUS_INVALID_PARAMS);
3787
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003788 hci_dev_lock(hdev);
3789
3790 hdev->le_scan_interval = interval;
3791 hdev->le_scan_window = window;
3792
3793 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3794
3795 hci_dev_unlock(hdev);
3796
3797 return err;
3798}
3799
Johan Hedberg33e38b32013-03-15 17:07:05 -05003800static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3801{
3802 struct pending_cmd *cmd;
3803
3804 BT_DBG("status 0x%02x", status);
3805
3806 hci_dev_lock(hdev);
3807
3808 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3809 if (!cmd)
3810 goto unlock;
3811
3812 if (status) {
3813 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3814 mgmt_status(status));
3815 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003816 struct mgmt_mode *cp = cmd->param;
3817
3818 if (cp->val)
3819 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3820 else
3821 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3822
Johan Hedberg33e38b32013-03-15 17:07:05 -05003823 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3824 new_settings(hdev, cmd->sk);
3825 }
3826
3827 mgmt_pending_remove(cmd);
3828
3829unlock:
3830 hci_dev_unlock(hdev);
3831}
3832
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003833static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003834 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003835{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003836 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003837 struct pending_cmd *cmd;
3838 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003839 int err;
3840
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003841 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003842
Johan Hedberg56f87902013-10-02 13:43:13 +03003843 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3844 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003845 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3846 MGMT_STATUS_NOT_SUPPORTED);
3847
Johan Hedberga7e80f22013-01-09 16:05:19 +02003848 if (cp->val != 0x00 && cp->val != 0x01)
3849 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3850 MGMT_STATUS_INVALID_PARAMS);
3851
Johan Hedberg5400c042012-02-21 16:40:33 +02003852 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003853 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003854 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003855
3856 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003857 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003858 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003859
3860 hci_dev_lock(hdev);
3861
Johan Hedberg05cbf292013-03-15 17:07:07 -05003862 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3863 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3864 MGMT_STATUS_BUSY);
3865 goto unlock;
3866 }
3867
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003868 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3869 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3870 hdev);
3871 goto unlock;
3872 }
3873
Johan Hedberg33e38b32013-03-15 17:07:05 -05003874 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3875 data, len);
3876 if (!cmd) {
3877 err = -ENOMEM;
3878 goto unlock;
3879 }
3880
3881 hci_req_init(&req, hdev);
3882
Johan Hedberg406d7802013-03-15 17:07:09 -05003883 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003884
3885 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003886 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003887 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003888 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003889 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003890 }
3891
Johan Hedberg33e38b32013-03-15 17:07:05 -05003892unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003893 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003894
Antti Julkuf6422ec2011-06-22 13:11:56 +03003895 return err;
3896}
3897
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003898static void set_bredr_scan(struct hci_request *req)
3899{
3900 struct hci_dev *hdev = req->hdev;
3901 u8 scan = 0;
3902
3903 /* Ensure that fast connectable is disabled. This function will
3904 * not do anything if the page scan parameters are already what
3905 * they should be.
3906 */
3907 write_fast_connectable(req, false);
3908
3909 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3910 scan |= SCAN_PAGE;
3911 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3912 scan |= SCAN_INQUIRY;
3913
3914 if (scan)
3915 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3916}
3917
Johan Hedberg0663ca22013-10-02 13:43:14 +03003918static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3919{
3920 struct pending_cmd *cmd;
3921
3922 BT_DBG("status 0x%02x", status);
3923
3924 hci_dev_lock(hdev);
3925
3926 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3927 if (!cmd)
3928 goto unlock;
3929
3930 if (status) {
3931 u8 mgmt_err = mgmt_status(status);
3932
3933 /* We need to restore the flag if related HCI commands
3934 * failed.
3935 */
3936 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3937
3938 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3939 } else {
3940 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3941 new_settings(hdev, cmd->sk);
3942 }
3943
3944 mgmt_pending_remove(cmd);
3945
3946unlock:
3947 hci_dev_unlock(hdev);
3948}
3949
3950static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3951{
3952 struct mgmt_mode *cp = data;
3953 struct pending_cmd *cmd;
3954 struct hci_request req;
3955 int err;
3956
3957 BT_DBG("request for %s", hdev->name);
3958
3959 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3960 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3961 MGMT_STATUS_NOT_SUPPORTED);
3962
3963 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3964 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3965 MGMT_STATUS_REJECTED);
3966
3967 if (cp->val != 0x00 && cp->val != 0x01)
3968 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3969 MGMT_STATUS_INVALID_PARAMS);
3970
3971 hci_dev_lock(hdev);
3972
3973 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3974 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3975 goto unlock;
3976 }
3977
3978 if (!hdev_is_powered(hdev)) {
3979 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003980 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3981 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3982 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3983 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3984 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3985 }
3986
3987 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3988
3989 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3990 if (err < 0)
3991 goto unlock;
3992
3993 err = new_settings(hdev, sk);
3994 goto unlock;
3995 }
3996
3997 /* Reject disabling when powered on */
3998 if (!cp->val) {
3999 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4000 MGMT_STATUS_REJECTED);
4001 goto unlock;
4002 }
4003
4004 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
4005 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4006 MGMT_STATUS_BUSY);
4007 goto unlock;
4008 }
4009
4010 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4011 if (!cmd) {
4012 err = -ENOMEM;
4013 goto unlock;
4014 }
4015
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004016 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03004017 * generates the correct flags.
4018 */
4019 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4020
4021 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004022
4023 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4024 set_bredr_scan(&req);
4025
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004026 /* Since only the advertising data flags will change, there
4027 * is no need to update the scan response data.
4028 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004029 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004030
Johan Hedberg0663ca22013-10-02 13:43:14 +03004031 err = hci_req_run(&req, set_bredr_complete);
4032 if (err < 0)
4033 mgmt_pending_remove(cmd);
4034
4035unlock:
4036 hci_dev_unlock(hdev);
4037 return err;
4038}
4039
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004040static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4041 void *data, u16 len)
4042{
4043 struct mgmt_mode *cp = data;
4044 struct pending_cmd *cmd;
4045 u8 status;
4046 int err;
4047
4048 BT_DBG("request for %s", hdev->name);
4049
4050 status = mgmt_bredr_support(hdev);
4051 if (status)
4052 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4053 status);
4054
Marcel Holtmann5afeac12014-01-10 02:07:27 -08004055 if (!lmp_sc_capable(hdev) &&
4056 !test_bit(HCI_FORCE_SC, &hdev->dev_flags))
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004057 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4058 MGMT_STATUS_NOT_SUPPORTED);
4059
4060 if (cp->val != 0x00 && cp->val != 0x01)
4061 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4062 MGMT_STATUS_INVALID_PARAMS);
4063
4064 hci_dev_lock(hdev);
4065
4066 if (!hdev_is_powered(hdev)) {
4067 bool changed;
4068
4069 if (cp->val)
4070 changed = !test_and_set_bit(HCI_SC_ENABLED,
4071 &hdev->dev_flags);
4072 else
4073 changed = test_and_clear_bit(HCI_SC_ENABLED,
4074 &hdev->dev_flags);
4075
4076 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4077 if (err < 0)
4078 goto failed;
4079
4080 if (changed)
4081 err = new_settings(hdev, sk);
4082
4083 goto failed;
4084 }
4085
4086 if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
4087 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4088 MGMT_STATUS_BUSY);
4089 goto failed;
4090 }
4091
4092 if (!!cp->val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
4093 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4094 goto failed;
4095 }
4096
4097 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4098 if (!cmd) {
4099 err = -ENOMEM;
4100 goto failed;
4101 }
4102
4103 err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &cp->val);
4104 if (err < 0) {
4105 mgmt_pending_remove(cmd);
4106 goto failed;
4107 }
4108
4109failed:
4110 hci_dev_unlock(hdev);
4111 return err;
4112}
4113
Johan Hedberg3f706b72013-01-20 14:27:16 +02004114static bool ltk_is_valid(struct mgmt_ltk_info *key)
4115{
Johan Hedberg44b20d32013-01-20 14:27:17 +02004116 if (key->authenticated != 0x00 && key->authenticated != 0x01)
4117 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004118 if (key->master != 0x00 && key->master != 0x01)
4119 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004120 if (!bdaddr_type_is_le(key->addr.type))
4121 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004122 return true;
4123}
4124
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004125static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004126 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004127{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004128 struct mgmt_cp_load_long_term_keys *cp = cp_data;
4129 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004130 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004131
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004132 BT_DBG("request for %s", hdev->name);
4133
4134 if (!lmp_le_capable(hdev))
4135 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4136 MGMT_STATUS_NOT_SUPPORTED);
4137
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004138 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004139
4140 expected_len = sizeof(*cp) + key_count *
4141 sizeof(struct mgmt_ltk_info);
4142 if (expected_len != len) {
4143 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004144 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004145 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02004146 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004147 }
4148
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004149 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004150
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004151 for (i = 0; i < key_count; i++) {
4152 struct mgmt_ltk_info *key = &cp->keys[i];
4153
Johan Hedberg3f706b72013-01-20 14:27:16 +02004154 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004155 return cmd_status(sk, hdev->id,
4156 MGMT_OP_LOAD_LONG_TERM_KEYS,
4157 MGMT_STATUS_INVALID_PARAMS);
4158 }
4159
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004160 hci_dev_lock(hdev);
4161
4162 hci_smp_ltks_clear(hdev);
4163
4164 for (i = 0; i < key_count; i++) {
4165 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004166 u8 type, addr_type;
4167
4168 if (key->addr.type == BDADDR_LE_PUBLIC)
4169 addr_type = ADDR_LE_DEV_PUBLIC;
4170 else
4171 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004172
4173 if (key->master)
4174 type = HCI_SMP_LTK;
4175 else
4176 type = HCI_SMP_LTK_SLAVE;
4177
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004178 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004179 type, 0, key->authenticated, key->val,
4180 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004181 }
4182
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004183 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4184 NULL, 0);
4185
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004186 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004187
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004188 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004189}
4190
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004191static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004192 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4193 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004194 bool var_len;
4195 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004196} mgmt_handlers[] = {
4197 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004198 { read_version, false, MGMT_READ_VERSION_SIZE },
4199 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4200 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4201 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4202 { set_powered, false, MGMT_SETTING_SIZE },
4203 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4204 { set_connectable, false, MGMT_SETTING_SIZE },
4205 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4206 { set_pairable, false, MGMT_SETTING_SIZE },
4207 { set_link_security, false, MGMT_SETTING_SIZE },
4208 { set_ssp, false, MGMT_SETTING_SIZE },
4209 { set_hs, false, MGMT_SETTING_SIZE },
4210 { set_le, false, MGMT_SETTING_SIZE },
4211 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4212 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4213 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4214 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4215 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4216 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4217 { disconnect, false, MGMT_DISCONNECT_SIZE },
4218 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4219 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4220 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4221 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4222 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4223 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4224 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4225 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4226 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4227 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4228 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4229 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
Marcel Holtmannec109112014-01-10 02:07:30 -08004230 { add_remote_oob_data, true, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
Johan Hedbergbe22b542012-03-01 22:24:41 +02004231 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4232 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4233 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4234 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4235 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4236 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004237 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004238 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004239 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004240 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004241 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004242 { set_secure_conn, false, MGMT_SETTING_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004243};
4244
4245
Johan Hedberg03811012010-12-08 00:21:06 +02004246int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4247{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004248 void *buf;
4249 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004250 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004251 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004252 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004253 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004254 int err;
4255
4256 BT_DBG("got %zu bytes", msglen);
4257
4258 if (msglen < sizeof(*hdr))
4259 return -EINVAL;
4260
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004261 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004262 if (!buf)
4263 return -ENOMEM;
4264
4265 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4266 err = -EFAULT;
4267 goto done;
4268 }
4269
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004270 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004271 opcode = __le16_to_cpu(hdr->opcode);
4272 index = __le16_to_cpu(hdr->index);
4273 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004274
4275 if (len != msglen - sizeof(*hdr)) {
4276 err = -EINVAL;
4277 goto done;
4278 }
4279
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004280 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004281 hdev = hci_dev_get(index);
4282 if (!hdev) {
4283 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004284 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004285 goto done;
4286 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004287
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004288 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4289 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004290 err = cmd_status(sk, index, opcode,
4291 MGMT_STATUS_INVALID_INDEX);
4292 goto done;
4293 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004294 }
4295
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004296 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004297 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004298 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004299 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004300 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004301 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004302 }
4303
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004304 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004305 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004306 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004307 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004308 goto done;
4309 }
4310
Johan Hedbergbe22b542012-03-01 22:24:41 +02004311 handler = &mgmt_handlers[opcode];
4312
4313 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004314 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004315 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004316 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004317 goto done;
4318 }
4319
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004320 if (hdev)
4321 mgmt_init_hdev(sk, hdev);
4322
4323 cp = buf + sizeof(*hdr);
4324
Johan Hedbergbe22b542012-03-01 22:24:41 +02004325 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004326 if (err < 0)
4327 goto done;
4328
Johan Hedberg03811012010-12-08 00:21:06 +02004329 err = msglen;
4330
4331done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004332 if (hdev)
4333 hci_dev_put(hdev);
4334
Johan Hedberg03811012010-12-08 00:21:06 +02004335 kfree(buf);
4336 return err;
4337}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004338
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004339void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004340{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004341 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004342 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004343
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004344 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004345}
4346
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004347void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004348{
Johan Hedberg5f159032012-03-02 03:13:19 +02004349 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004350
Marcel Holtmann1514b892013-10-06 08:25:01 -07004351 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004352 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004353
Johan Hedberg744cf192011-11-08 20:40:14 +02004354 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004355
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004356 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004357}
4358
Johan Hedberg229ab392013-03-15 17:06:53 -05004359static void powered_complete(struct hci_dev *hdev, u8 status)
4360{
4361 struct cmd_lookup match = { NULL, hdev };
4362
4363 BT_DBG("status 0x%02x", status);
4364
4365 hci_dev_lock(hdev);
4366
4367 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4368
4369 new_settings(hdev, match.sk);
4370
4371 hci_dev_unlock(hdev);
4372
4373 if (match.sk)
4374 sock_put(match.sk);
4375}
4376
Johan Hedberg70da6242013-03-15 17:06:51 -05004377static int powered_update_hci(struct hci_dev *hdev)
4378{
Johan Hedberg890ea892013-03-15 17:06:52 -05004379 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004380 u8 link_sec;
4381
Johan Hedberg890ea892013-03-15 17:06:52 -05004382 hci_req_init(&req, hdev);
4383
Johan Hedberg70da6242013-03-15 17:06:51 -05004384 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4385 !lmp_host_ssp_capable(hdev)) {
4386 u8 ssp = 1;
4387
Johan Hedberg890ea892013-03-15 17:06:52 -05004388 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004389 }
4390
Johan Hedbergc73eee92013-04-19 18:35:21 +03004391 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4392 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004393 struct hci_cp_write_le_host_supported cp;
4394
4395 cp.le = 1;
4396 cp.simul = lmp_le_br_capable(hdev);
4397
4398 /* Check first if we already have the right
4399 * host state (host features set)
4400 */
4401 if (cp.le != lmp_host_le_capable(hdev) ||
4402 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004403 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4404 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004405 }
4406
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004407 if (lmp_le_capable(hdev)) {
4408 /* Set random address to static address if configured */
4409 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4410 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4411 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004412
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004413 /* Make sure the controller has a good default for
4414 * advertising data. This also applies to the case
4415 * where BR/EDR was toggled during the AUTO_OFF phase.
4416 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004417 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004418 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004419 update_scan_rsp_data(&req);
4420 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004421
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004422 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4423 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004424 }
4425
Johan Hedberg70da6242013-03-15 17:06:51 -05004426 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4427 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004428 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4429 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004430
4431 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004432 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4433 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004434 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004435 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004436 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004437 }
4438
Johan Hedberg229ab392013-03-15 17:06:53 -05004439 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004440}
4441
Johan Hedberg744cf192011-11-08 20:40:14 +02004442int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004443{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004444 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004445 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4446 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004447 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004448
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004449 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4450 return 0;
4451
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004452 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004453 if (powered_update_hci(hdev) == 0)
4454 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004455
Johan Hedberg229ab392013-03-15 17:06:53 -05004456 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4457 &match);
4458 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004459 }
4460
Johan Hedberg229ab392013-03-15 17:06:53 -05004461 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4462 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4463
4464 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4465 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4466 zero_cod, sizeof(zero_cod), NULL);
4467
4468new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004469 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004470
4471 if (match.sk)
4472 sock_put(match.sk);
4473
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004474 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004475}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004476
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004477void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004478{
4479 struct pending_cmd *cmd;
4480 u8 status;
4481
4482 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4483 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004484 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004485
4486 if (err == -ERFKILL)
4487 status = MGMT_STATUS_RFKILLED;
4488 else
4489 status = MGMT_STATUS_FAILED;
4490
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004491 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004492
4493 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004494}
4495
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004496void mgmt_discoverable_timeout(struct hci_dev *hdev)
4497{
4498 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004499
4500 hci_dev_lock(hdev);
4501
4502 /* When discoverable timeout triggers, then just make sure
4503 * the limited discoverable flag is cleared. Even in the case
4504 * of a timeout triggered from general discoverable, it is
4505 * safe to unconditionally clear the flag.
4506 */
4507 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004508 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004509
4510 hci_req_init(&req, hdev);
Johan Hedberg4b580612013-10-19 23:38:21 +03004511 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4512 u8 scan = SCAN_PAGE;
4513 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
4514 sizeof(scan), &scan);
4515 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004516 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004517 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004518 hci_req_run(&req, NULL);
4519
4520 hdev->discov_timeout = 0;
4521
Johan Hedberg9a43e252013-10-20 19:00:07 +03004522 new_settings(hdev, NULL);
4523
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004524 hci_dev_unlock(hdev);
4525}
4526
Marcel Holtmann86a75642013-10-15 06:33:54 -07004527void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004528{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004529 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004530
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004531 /* Nothing needed here if there's a pending command since that
4532 * commands request completion callback takes care of everything
4533 * necessary.
4534 */
4535 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004536 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004537
Johan Hedberg9a43e252013-10-20 19:00:07 +03004538 if (discoverable) {
Marcel Holtmann86a75642013-10-15 06:33:54 -07004539 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004540 } else {
4541 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmann86a75642013-10-15 06:33:54 -07004542 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004543 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004544
Johan Hedberg9a43e252013-10-20 19:00:07 +03004545 if (changed) {
4546 struct hci_request req;
4547
4548 /* In case this change in discoverable was triggered by
4549 * a disabling of connectable there could be a need to
4550 * update the advertising flags.
4551 */
4552 hci_req_init(&req, hdev);
4553 update_adv_data(&req);
4554 hci_req_run(&req, NULL);
4555
Marcel Holtmann86a75642013-10-15 06:33:54 -07004556 new_settings(hdev, NULL);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004557 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004558}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004559
Marcel Holtmanna3309162013-10-15 06:33:55 -07004560void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004561{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004562 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004563
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004564 /* Nothing needed here if there's a pending command since that
4565 * commands request completion callback takes care of everything
4566 * necessary.
4567 */
4568 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004569 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004570
Marcel Holtmanna3309162013-10-15 06:33:55 -07004571 if (connectable)
4572 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4573 else
4574 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004575
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004576 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004577 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004578}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004579
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004580void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004581{
Johan Hedbergca69b792011-11-11 18:10:00 +02004582 u8 mgmt_err = mgmt_status(status);
4583
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004584 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004585 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004586 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004587
4588 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004589 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004590 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004591}
4592
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004593void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4594 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004595{
Johan Hedberg86742e12011-11-07 23:13:38 +02004596 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004597
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004598 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004599
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004600 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004601 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004602 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004603 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004604 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004605 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004606
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004607 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004608}
Johan Hedbergf7520542011-01-20 12:34:39 +02004609
Marcel Holtmann083368f2013-10-15 14:26:29 -07004610void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004611{
4612 struct mgmt_ev_new_long_term_key ev;
4613
4614 memset(&ev, 0, sizeof(ev));
4615
4616 ev.store_hint = persistent;
4617 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004618 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004619 ev.key.authenticated = key->authenticated;
4620 ev.key.enc_size = key->enc_size;
4621 ev.key.ediv = key->ediv;
4622
4623 if (key->type == HCI_SMP_LTK)
4624 ev.key.master = 1;
4625
4626 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4627 memcpy(ev.key.val, key->val, sizeof(key->val));
4628
Marcel Holtmann083368f2013-10-15 14:26:29 -07004629 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004630}
4631
Marcel Holtmann94933992013-10-15 10:26:39 -07004632static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4633 u8 data_len)
4634{
4635 eir[eir_len++] = sizeof(type) + data_len;
4636 eir[eir_len++] = type;
4637 memcpy(&eir[eir_len], data, data_len);
4638 eir_len += data_len;
4639
4640 return eir_len;
4641}
4642
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004643void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4644 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4645 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004646{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004647 char buf[512];
4648 struct mgmt_ev_device_connected *ev = (void *) buf;
4649 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004650
Johan Hedbergb644ba32012-01-17 21:48:47 +02004651 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004652 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004653
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004654 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004655
Johan Hedbergb644ba32012-01-17 21:48:47 +02004656 if (name_len > 0)
4657 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004658 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004659
4660 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004661 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004662 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004663
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004664 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004665
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004666 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4667 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004668}
4669
Johan Hedberg8962ee72011-01-20 12:40:27 +02004670static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4671{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004672 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004673 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004674 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004675
Johan Hedberg88c3df12012-02-09 14:27:38 +02004676 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4677 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004678
Johan Hedbergaee9b212012-02-18 15:07:59 +02004679 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004680 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004681
4682 *sk = cmd->sk;
4683 sock_hold(*sk);
4684
Johan Hedberga664b5b2011-02-19 12:06:02 -03004685 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004686}
4687
Johan Hedberg124f6e32012-02-09 13:50:12 +02004688static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004689{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004690 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004691 struct mgmt_cp_unpair_device *cp = cmd->param;
4692 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004693
4694 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004695 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4696 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004697
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004698 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4699
Johan Hedbergaee9b212012-02-18 15:07:59 +02004700 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004701
4702 mgmt_pending_remove(cmd);
4703}
4704
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004705void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4706 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004707{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004708 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004709 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004710
Andre Guedes57eb7762013-10-30 19:01:41 -03004711 if (link_type != ACL_LINK && link_type != LE_LINK)
4712 return;
4713
Johan Hedberg744cf192011-11-08 20:40:14 +02004714 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004715
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004716 bacpy(&ev.addr.bdaddr, bdaddr);
4717 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4718 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004719
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004720 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004721
4722 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004723 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004724
Johan Hedberg124f6e32012-02-09 13:50:12 +02004725 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004726 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004727}
4728
Marcel Holtmann78929242013-10-06 23:55:47 -07004729void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4730 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004731{
Andre Guedes3655bba2013-10-30 19:01:40 -03004732 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
4733 struct mgmt_cp_disconnect *cp;
Johan Hedberg88c3df12012-02-09 14:27:38 +02004734 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004735 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004736
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004737 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4738 hdev);
4739
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004740 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004741 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004742 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004743
Andre Guedes3655bba2013-10-30 19:01:40 -03004744 cp = cmd->param;
4745
4746 if (bacmp(bdaddr, &cp->addr.bdaddr))
4747 return;
4748
4749 if (cp->addr.type != bdaddr_type)
4750 return;
4751
Johan Hedberg88c3df12012-02-09 14:27:38 +02004752 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes3655bba2013-10-30 19:01:40 -03004753 rp.addr.type = bdaddr_type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004754
Marcel Holtmann78929242013-10-06 23:55:47 -07004755 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4756 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004757
Johan Hedberga664b5b2011-02-19 12:06:02 -03004758 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004759}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004760
Marcel Holtmann445608d2013-10-06 23:55:48 -07004761void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4762 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004763{
4764 struct mgmt_ev_connect_failed ev;
4765
Johan Hedberg4c659c32011-11-07 23:13:39 +02004766 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004767 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004768 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004769
Marcel Holtmann445608d2013-10-06 23:55:48 -07004770 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004771}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004772
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004773void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004774{
4775 struct mgmt_ev_pin_code_request ev;
4776
Johan Hedbergd8457692012-02-17 14:24:57 +02004777 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004778 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004779 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004780
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004781 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004782}
4783
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004784void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4785 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004786{
4787 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004788 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004789
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004790 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004791 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004792 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004793
Johan Hedbergd8457692012-02-17 14:24:57 +02004794 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004795 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004796
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004797 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
4798 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004799
Johan Hedberga664b5b2011-02-19 12:06:02 -03004800 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004801}
4802
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004803void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4804 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004805{
4806 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004807 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004808
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004809 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004810 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004811 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004812
Johan Hedbergd8457692012-02-17 14:24:57 +02004813 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004814 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004815
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004816 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
4817 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004818
Johan Hedberga664b5b2011-02-19 12:06:02 -03004819 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004820}
Johan Hedberga5c29682011-02-19 12:05:57 -03004821
Johan Hedberg744cf192011-11-08 20:40:14 +02004822int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004823 u8 link_type, u8 addr_type, __le32 value,
4824 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004825{
4826 struct mgmt_ev_user_confirm_request ev;
4827
Johan Hedberg744cf192011-11-08 20:40:14 +02004828 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004829
Johan Hedberg272d90d2012-02-09 15:26:12 +02004830 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004831 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004832 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004833 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004834
Johan Hedberg744cf192011-11-08 20:40:14 +02004835 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004836 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004837}
4838
Johan Hedberg272d90d2012-02-09 15:26:12 +02004839int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004840 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004841{
4842 struct mgmt_ev_user_passkey_request ev;
4843
4844 BT_DBG("%s", hdev->name);
4845
Johan Hedberg272d90d2012-02-09 15:26:12 +02004846 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004847 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004848
4849 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004850 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004851}
4852
Brian Gix0df4c182011-11-16 13:53:13 -08004853static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004854 u8 link_type, u8 addr_type, u8 status,
4855 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004856{
4857 struct pending_cmd *cmd;
4858 struct mgmt_rp_user_confirm_reply rp;
4859 int err;
4860
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004861 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004862 if (!cmd)
4863 return -ENOENT;
4864
Johan Hedberg272d90d2012-02-09 15:26:12 +02004865 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004866 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004867 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004868 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004869
Johan Hedberga664b5b2011-02-19 12:06:02 -03004870 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004871
4872 return err;
4873}
4874
Johan Hedberg744cf192011-11-08 20:40:14 +02004875int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004876 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004877{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004878 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004879 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004880}
4881
Johan Hedberg272d90d2012-02-09 15:26:12 +02004882int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004883 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004884{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004885 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004886 status,
4887 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004888}
Johan Hedberg2a611692011-02-19 12:06:00 -03004889
Brian Gix604086b2011-11-23 08:28:33 -08004890int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004891 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004892{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004893 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004894 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004895}
4896
Johan Hedberg272d90d2012-02-09 15:26:12 +02004897int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004898 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004899{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004900 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004901 status,
4902 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004903}
4904
Johan Hedberg92a25252012-09-06 18:39:26 +03004905int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4906 u8 link_type, u8 addr_type, u32 passkey,
4907 u8 entered)
4908{
4909 struct mgmt_ev_passkey_notify ev;
4910
4911 BT_DBG("%s", hdev->name);
4912
4913 bacpy(&ev.addr.bdaddr, bdaddr);
4914 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4915 ev.passkey = __cpu_to_le32(passkey);
4916 ev.entered = entered;
4917
4918 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4919}
4920
Marcel Holtmanne5460992013-10-15 14:26:23 -07004921void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4922 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004923{
4924 struct mgmt_ev_auth_failed ev;
4925
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004926 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004927 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004928 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004929
Marcel Holtmanne5460992013-10-15 14:26:23 -07004930 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004931}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004932
Marcel Holtmann464996a2013-10-15 14:26:24 -07004933void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004934{
4935 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07004936 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004937
4938 if (status) {
4939 u8 mgmt_err = mgmt_status(status);
4940 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004941 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07004942 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004943 }
4944
Marcel Holtmann464996a2013-10-15 14:26:24 -07004945 if (test_bit(HCI_AUTH, &hdev->flags))
4946 changed = !test_and_set_bit(HCI_LINK_SECURITY,
4947 &hdev->dev_flags);
4948 else
4949 changed = test_and_clear_bit(HCI_LINK_SECURITY,
4950 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02004951
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004952 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004953 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004954
Johan Hedberg47990ea2012-02-22 11:58:37 +02004955 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07004956 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004957
4958 if (match.sk)
4959 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004960}
4961
Johan Hedberg890ea892013-03-15 17:06:52 -05004962static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004963{
Johan Hedberg890ea892013-03-15 17:06:52 -05004964 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004965 struct hci_cp_write_eir cp;
4966
Johan Hedberg976eb202012-10-24 21:12:01 +03004967 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004968 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004969
Johan Hedbergc80da272012-02-22 15:38:48 +02004970 memset(hdev->eir, 0, sizeof(hdev->eir));
4971
Johan Hedbergcacaf522012-02-21 00:52:42 +02004972 memset(&cp, 0, sizeof(cp));
4973
Johan Hedberg890ea892013-03-15 17:06:52 -05004974 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004975}
4976
Marcel Holtmann3e248562013-10-15 14:26:25 -07004977void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004978{
4979 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004980 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004981 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004982
4983 if (status) {
4984 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004985
4986 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004987 &hdev->dev_flags)) {
4988 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004989 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004990 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004991
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004992 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4993 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004994 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004995 }
4996
4997 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004998 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004999 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005000 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
5001 if (!changed)
5002 changed = test_and_clear_bit(HCI_HS_ENABLED,
5003 &hdev->dev_flags);
5004 else
5005 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005006 }
5007
5008 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
5009
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005010 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07005011 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005012
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005013 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005014 sock_put(match.sk);
5015
Johan Hedberg890ea892013-03-15 17:06:52 -05005016 hci_req_init(&req, hdev);
5017
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005018 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05005019 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005020 else
Johan Hedberg890ea892013-03-15 17:06:52 -05005021 clear_eir(&req);
5022
5023 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005024}
5025
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005026void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
5027{
5028 struct cmd_lookup match = { NULL, hdev };
5029 bool changed = false;
5030
5031 if (status) {
5032 u8 mgmt_err = mgmt_status(status);
5033
5034 if (enable && test_and_clear_bit(HCI_SC_ENABLED,
5035 &hdev->dev_flags))
5036 new_settings(hdev, NULL);
5037
5038 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5039 cmd_status_rsp, &mgmt_err);
5040 return;
5041 }
5042
5043 if (enable)
5044 changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
5045 else
5046 changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
5047
5048 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5049 settings_rsp, &match);
5050
5051 if (changed)
5052 new_settings(hdev, match.sk);
5053
5054 if (match.sk)
5055 sock_put(match.sk);
5056}
5057
Johan Hedberg92da6092013-03-15 17:06:55 -05005058static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02005059{
5060 struct cmd_lookup *match = data;
5061
Johan Hedberg90e70452012-02-23 23:09:40 +02005062 if (match->sk == NULL) {
5063 match->sk = cmd->sk;
5064 sock_hold(match->sk);
5065 }
Johan Hedberg90e70452012-02-23 23:09:40 +02005066}
5067
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005068void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
5069 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005070{
Johan Hedberg90e70452012-02-23 23:09:40 +02005071 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005072
Johan Hedberg92da6092013-03-15 17:06:55 -05005073 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
5074 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
5075 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02005076
5077 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005078 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
5079 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02005080
5081 if (match.sk)
5082 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005083}
5084
Marcel Holtmann7667da32013-10-15 14:26:27 -07005085void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02005086{
Johan Hedbergb312b1612011-03-16 14:29:37 +02005087 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05005088 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005089
Johan Hedberg13928972013-03-15 17:07:00 -05005090 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07005091 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005092
5093 memset(&ev, 0, sizeof(ev));
5094 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005095 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005096
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005097 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05005098 if (!cmd) {
5099 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02005100
Johan Hedberg13928972013-03-15 17:07:00 -05005101 /* If this is a HCI command related to powering on the
5102 * HCI dev don't send any mgmt signals.
5103 */
5104 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07005105 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005106 }
5107
Marcel Holtmann7667da32013-10-15 14:26:27 -07005108 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
5109 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005110}
Szymon Jancc35938b2011-03-22 13:12:21 +01005111
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005112void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
5113 u8 *randomizer192, u8 *hash256,
5114 u8 *randomizer256, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01005115{
5116 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01005117
Johan Hedberg744cf192011-11-08 20:40:14 +02005118 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01005119
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005120 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01005121 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005122 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01005123
5124 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005125 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
5126 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01005127 } else {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005128 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
5129 hash256 && randomizer256) {
5130 struct mgmt_rp_read_local_oob_ext_data rp;
Szymon Jancc35938b2011-03-22 13:12:21 +01005131
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005132 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
5133 memcpy(rp.randomizer192, randomizer192,
5134 sizeof(rp.randomizer192));
Szymon Jancc35938b2011-03-22 13:12:21 +01005135
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005136 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
5137 memcpy(rp.randomizer256, randomizer256,
5138 sizeof(rp.randomizer256));
5139
5140 cmd_complete(cmd->sk, hdev->id,
5141 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5142 &rp, sizeof(rp));
5143 } else {
5144 struct mgmt_rp_read_local_oob_data rp;
5145
5146 memcpy(rp.hash, hash192, sizeof(rp.hash));
5147 memcpy(rp.randomizer, randomizer192,
5148 sizeof(rp.randomizer));
5149
5150 cmd_complete(cmd->sk, hdev->id,
5151 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5152 &rp, sizeof(rp));
5153 }
Szymon Jancc35938b2011-03-22 13:12:21 +01005154 }
5155
5156 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01005157}
Johan Hedberge17acd42011-03-30 23:57:16 +03005158
Marcel Holtmann901801b2013-10-06 23:55:51 -07005159void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5160 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
5161 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03005162{
Johan Hedberge319d2e2012-01-15 19:51:59 +02005163 char buf[512];
5164 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02005165 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03005166
Andre Guedes12602d02013-04-30 15:29:40 -03005167 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005168 return;
Andre Guedes12602d02013-04-30 15:29:40 -03005169
Johan Hedberg1dc06092012-01-15 21:01:23 +02005170 /* Leave 5 bytes for a potential CoD field */
5171 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005172 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03005173
Johan Hedberg1dc06092012-01-15 21:01:23 +02005174 memset(buf, 0, sizeof(buf));
5175
Johan Hedberge319d2e2012-01-15 19:51:59 +02005176 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005177 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02005178 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02005179 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305180 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02005181 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305182 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03005183
Johan Hedberg1dc06092012-01-15 21:01:23 +02005184 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02005185 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03005186
Johan Hedberg1dc06092012-01-15 21:01:23 +02005187 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
5188 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005189 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005190
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005191 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005192 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03005193
Marcel Holtmann901801b2013-10-06 23:55:51 -07005194 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03005195}
Johan Hedberga88a9652011-03-30 13:18:12 +03005196
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005197void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5198 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03005199{
Johan Hedbergb644ba32012-01-17 21:48:47 +02005200 struct mgmt_ev_device_found *ev;
5201 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
5202 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03005203
Johan Hedbergb644ba32012-01-17 21:48:47 +02005204 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03005205
Johan Hedbergb644ba32012-01-17 21:48:47 +02005206 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03005207
Johan Hedbergb644ba32012-01-17 21:48:47 +02005208 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005209 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005210 ev->rssi = rssi;
5211
5212 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005213 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005214
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005215 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005216
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005217 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03005218}
Johan Hedberg314b2382011-04-27 10:29:57 -04005219
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005220void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04005221{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005222 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02005223 struct pending_cmd *cmd;
5224
Andre Guedes343fb142011-11-22 17:14:19 -03005225 BT_DBG("%s discovering %u", hdev->name, discovering);
5226
Johan Hedberg164a6e72011-11-01 17:06:44 +02005227 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005228 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005229 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005230 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005231
5232 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02005233 u8 type = hdev->discovery.type;
5234
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005235 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
5236 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02005237 mgmt_pending_remove(cmd);
5238 }
5239
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005240 memset(&ev, 0, sizeof(ev));
5241 ev.type = hdev->discovery.type;
5242 ev.discovering = discovering;
5243
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005244 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04005245}
Antti Julku5e762442011-08-25 16:48:02 +03005246
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005247int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005248{
5249 struct pending_cmd *cmd;
5250 struct mgmt_ev_device_blocked ev;
5251
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005252 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005253
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005254 bacpy(&ev.addr.bdaddr, bdaddr);
5255 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005256
Johan Hedberg744cf192011-11-08 20:40:14 +02005257 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005258 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005259}
5260
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005261int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005262{
5263 struct pending_cmd *cmd;
5264 struct mgmt_ev_device_unblocked ev;
5265
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005266 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005267
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005268 bacpy(&ev.addr.bdaddr, bdaddr);
5269 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005270
Johan Hedberg744cf192011-11-08 20:40:14 +02005271 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005272 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005273}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005274
5275static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5276{
5277 BT_DBG("%s status %u", hdev->name, status);
5278
5279 /* Clear the advertising mgmt setting if we failed to re-enable it */
5280 if (status) {
5281 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005282 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005283 }
5284}
5285
5286void mgmt_reenable_advertising(struct hci_dev *hdev)
5287{
5288 struct hci_request req;
5289
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005290 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005291 return;
5292
5293 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5294 return;
5295
5296 hci_req_init(&req, hdev);
5297 enable_advertising(&req);
5298
5299 /* If this fails we have no option but to let user space know
5300 * that we've disabled advertising.
5301 */
5302 if (hci_req_run(&req, adv_enable_complete) < 0) {
5303 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005304 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005305 }
5306}