blob: bbe30c9834922294e3e937c426d21b06d1aa6ec4 [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 Holtmann9ab8cf32013-10-02 05:18:31 -070037#define MGMT_REVISION 4
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 */
131 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
132 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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200204
Andre Guedes790eff42012-06-07 19:05:46 -0300205 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200221 kfree_skb(skb);
222
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300223 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200224}
225
Johan Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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;
Johan Hedberg03811012010-12-08 00:21:06 +0200367
Andre Guedesed3fa312012-07-24 15:03:46 -0300368 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300369 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500370 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
371 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300372 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200373 settings |= MGMT_SETTING_BREDR;
374 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700375
376 if (lmp_ssp_capable(hdev)) {
377 settings |= MGMT_SETTING_SSP;
378 settings |= MGMT_SETTING_HS;
379 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800380
Marcel Holtmann5afeac142014-01-10 02:07:27 -0800381 if (lmp_sc_capable(hdev) ||
382 test_bit(HCI_FORCE_SC, &hdev->dev_flags))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800383 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700384 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100385
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300386 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200387 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300388 settings |= MGMT_SETTING_ADVERTISING;
389 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391 return settings;
392}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200393
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200394static u32 get_current_settings(struct hci_dev *hdev)
395{
396 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200397
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200398 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100399 settings |= MGMT_SETTING_POWERED;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_CONNECTABLE;
403
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500404 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
405 settings |= MGMT_SETTING_FAST_CONNECTABLE;
406
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200407 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_DISCOVERABLE;
409
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200410 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_PAIRABLE;
412
Johan Hedberg56f87902013-10-02 13:43:13 +0300413 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_BREDR;
415
Johan Hedberg06199cf2012-02-22 16:37:11 +0200416 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg47990ea2012-02-22 11:58:37 +0200419 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200421
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200422 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200423 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200424
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200425 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
426 settings |= MGMT_SETTING_HS;
427
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200428 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300429 settings |= MGMT_SETTING_ADVERTISING;
430
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800431 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
432 settings |= MGMT_SETTING_SECURE_CONN;
433
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200434 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200435}
436
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300437#define PNP_INFO_SVCLASS_ID 0x1200
438
Johan Hedberg213202e2013-01-27 00:31:33 +0200439static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
440{
441 u8 *ptr = data, *uuids_start = NULL;
442 struct bt_uuid *uuid;
443
444 if (len < 4)
445 return ptr;
446
447 list_for_each_entry(uuid, &hdev->uuids, list) {
448 u16 uuid16;
449
450 if (uuid->size != 16)
451 continue;
452
453 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
454 if (uuid16 < 0x1100)
455 continue;
456
457 if (uuid16 == PNP_INFO_SVCLASS_ID)
458 continue;
459
460 if (!uuids_start) {
461 uuids_start = ptr;
462 uuids_start[0] = 1;
463 uuids_start[1] = EIR_UUID16_ALL;
464 ptr += 2;
465 }
466
467 /* Stop if not enough space to put next UUID */
468 if ((ptr - data) + sizeof(u16) > len) {
469 uuids_start[1] = EIR_UUID16_SOME;
470 break;
471 }
472
473 *ptr++ = (uuid16 & 0x00ff);
474 *ptr++ = (uuid16 & 0xff00) >> 8;
475 uuids_start[0] += sizeof(uuid16);
476 }
477
478 return ptr;
479}
480
Johan Hedbergcdf19632013-01-27 00:31:34 +0200481static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
482{
483 u8 *ptr = data, *uuids_start = NULL;
484 struct bt_uuid *uuid;
485
486 if (len < 6)
487 return ptr;
488
489 list_for_each_entry(uuid, &hdev->uuids, list) {
490 if (uuid->size != 32)
491 continue;
492
493 if (!uuids_start) {
494 uuids_start = ptr;
495 uuids_start[0] = 1;
496 uuids_start[1] = EIR_UUID32_ALL;
497 ptr += 2;
498 }
499
500 /* Stop if not enough space to put next UUID */
501 if ((ptr - data) + sizeof(u32) > len) {
502 uuids_start[1] = EIR_UUID32_SOME;
503 break;
504 }
505
506 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
507 ptr += sizeof(u32);
508 uuids_start[0] += sizeof(u32);
509 }
510
511 return ptr;
512}
513
Johan Hedbergc00d5752013-01-27 00:31:35 +0200514static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
515{
516 u8 *ptr = data, *uuids_start = NULL;
517 struct bt_uuid *uuid;
518
519 if (len < 18)
520 return ptr;
521
522 list_for_each_entry(uuid, &hdev->uuids, list) {
523 if (uuid->size != 128)
524 continue;
525
526 if (!uuids_start) {
527 uuids_start = ptr;
528 uuids_start[0] = 1;
529 uuids_start[1] = EIR_UUID128_ALL;
530 ptr += 2;
531 }
532
533 /* Stop if not enough space to put next UUID */
534 if ((ptr - data) + 16 > len) {
535 uuids_start[1] = EIR_UUID128_SOME;
536 break;
537 }
538
539 memcpy(ptr, uuid->uuid, 16);
540 ptr += 16;
541 uuids_start[0] += 16;
542 }
543
544 return ptr;
545}
546
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300547static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
548{
549 struct pending_cmd *cmd;
550
551 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
552 if (cmd->opcode == opcode)
553 return cmd;
554 }
555
556 return NULL;
557}
558
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700559static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
560{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700561 u8 ad_len = 0;
562 size_t name_len;
563
564 name_len = strlen(hdev->dev_name);
565 if (name_len > 0) {
566 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
567
568 if (name_len > max_len) {
569 name_len = max_len;
570 ptr[1] = EIR_NAME_SHORT;
571 } else
572 ptr[1] = EIR_NAME_COMPLETE;
573
574 ptr[0] = name_len + 1;
575
576 memcpy(ptr + 2, hdev->dev_name, name_len);
577
578 ad_len += (name_len + 2);
579 ptr += (name_len + 2);
580 }
581
582 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700583}
584
585static void update_scan_rsp_data(struct hci_request *req)
586{
587 struct hci_dev *hdev = req->hdev;
588 struct hci_cp_le_set_scan_rsp_data cp;
589 u8 len;
590
Johan Hedberg7751ef12013-10-19 23:38:15 +0300591 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700592 return;
593
594 memset(&cp, 0, sizeof(cp));
595
596 len = create_scan_rsp_data(hdev, cp.data);
597
Johan Hedbergeb438b52013-10-16 15:31:07 +0300598 if (hdev->scan_rsp_data_len == len &&
599 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700600 return;
601
Johan Hedbergeb438b52013-10-16 15:31:07 +0300602 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
603 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700604
605 cp.length = len;
606
607 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
608}
609
Johan Hedberg9a43e252013-10-20 19:00:07 +0300610static u8 get_adv_discov_flags(struct hci_dev *hdev)
611{
612 struct pending_cmd *cmd;
613
614 /* If there's a pending mgmt command the flags will not yet have
615 * their final values, so check for this first.
616 */
617 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
618 if (cmd) {
619 struct mgmt_mode *cp = cmd->param;
620 if (cp->val == 0x01)
621 return LE_AD_GENERAL;
622 else if (cp->val == 0x02)
623 return LE_AD_LIMITED;
624 } else {
625 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
626 return LE_AD_LIMITED;
627 else if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
628 return LE_AD_GENERAL;
629 }
630
631 return 0;
632}
633
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700634static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700635{
636 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700637
Johan Hedberg9a43e252013-10-20 19:00:07 +0300638 flags |= get_adv_discov_flags(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700639
640 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
641 if (lmp_le_br_capable(hdev))
642 flags |= LE_AD_SIM_LE_BREDR_CTRL;
643 if (lmp_host_le_br_capable(hdev))
644 flags |= LE_AD_SIM_LE_BREDR_HOST;
645 } else {
646 flags |= LE_AD_NO_BREDR;
647 }
648
649 if (flags) {
650 BT_DBG("adv flags 0x%02x", flags);
651
652 ptr[0] = 2;
653 ptr[1] = EIR_FLAGS;
654 ptr[2] = flags;
655
656 ad_len += 3;
657 ptr += 3;
658 }
659
660 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
661 ptr[0] = 2;
662 ptr[1] = EIR_TX_POWER;
663 ptr[2] = (u8) hdev->adv_tx_power;
664
665 ad_len += 3;
666 ptr += 3;
667 }
668
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700669 return ad_len;
670}
671
Marcel Holtmann5947f4b2013-10-16 00:16:50 -0700672static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700673{
674 struct hci_dev *hdev = req->hdev;
675 struct hci_cp_le_set_adv_data cp;
676 u8 len;
677
Johan Hedberg10994ce2013-10-19 23:38:16 +0300678 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700679 return;
680
681 memset(&cp, 0, sizeof(cp));
682
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700683 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700684
685 if (hdev->adv_data_len == len &&
686 memcmp(cp.data, hdev->adv_data, len) == 0)
687 return;
688
689 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
690 hdev->adv_data_len = len;
691
692 cp.length = len;
693
694 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
695}
696
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300697static void create_eir(struct hci_dev *hdev, u8 *data)
698{
699 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300700 size_t name_len;
701
702 name_len = strlen(hdev->dev_name);
703
704 if (name_len > 0) {
705 /* EIR Data type */
706 if (name_len > 48) {
707 name_len = 48;
708 ptr[1] = EIR_NAME_SHORT;
709 } else
710 ptr[1] = EIR_NAME_COMPLETE;
711
712 /* EIR Data length */
713 ptr[0] = name_len + 1;
714
715 memcpy(ptr + 2, hdev->dev_name, name_len);
716
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300717 ptr += (name_len + 2);
718 }
719
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100720 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700721 ptr[0] = 2;
722 ptr[1] = EIR_TX_POWER;
723 ptr[2] = (u8) hdev->inq_tx_power;
724
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700725 ptr += 3;
726 }
727
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700728 if (hdev->devid_source > 0) {
729 ptr[0] = 9;
730 ptr[1] = EIR_DEVICE_ID;
731
732 put_unaligned_le16(hdev->devid_source, ptr + 2);
733 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
734 put_unaligned_le16(hdev->devid_product, ptr + 6);
735 put_unaligned_le16(hdev->devid_version, ptr + 8);
736
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700737 ptr += 10;
738 }
739
Johan Hedberg213202e2013-01-27 00:31:33 +0200740 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200741 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200742 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300743}
744
Johan Hedberg890ea892013-03-15 17:06:52 -0500745static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300746{
Johan Hedberg890ea892013-03-15 17:06:52 -0500747 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300748 struct hci_cp_write_eir cp;
749
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200750 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500751 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200752
Johan Hedberg976eb202012-10-24 21:12:01 +0300753 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500754 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300755
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200756 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500757 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300758
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200759 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500760 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300761
762 memset(&cp, 0, sizeof(cp));
763
764 create_eir(hdev, cp.data);
765
766 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500767 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300768
769 memcpy(hdev->eir, cp.data, sizeof(cp.data));
770
Johan Hedberg890ea892013-03-15 17:06:52 -0500771 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300772}
773
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200774static u8 get_service_classes(struct hci_dev *hdev)
775{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300776 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200777 u8 val = 0;
778
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300779 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200780 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200781
782 return val;
783}
784
Johan Hedberg890ea892013-03-15 17:06:52 -0500785static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200786{
Johan Hedberg890ea892013-03-15 17:06:52 -0500787 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200788 u8 cod[3];
789
790 BT_DBG("%s", hdev->name);
791
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200792 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500793 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200794
Johan Hedbergf87ea1d2013-10-19 23:38:17 +0300795 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
796 return;
797
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200798 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500799 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200800
801 cod[0] = hdev->minor_class;
802 cod[1] = hdev->major_class;
803 cod[2] = get_service_classes(hdev);
804
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700805 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
806 cod[1] |= 0x20;
807
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200808 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500809 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200810
Johan Hedberg890ea892013-03-15 17:06:52 -0500811 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200812}
813
Johan Hedberg7d785252011-12-15 00:47:39 +0200814static void service_cache_off(struct work_struct *work)
815{
816 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300817 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500818 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200819
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200820 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200821 return;
822
Johan Hedberg890ea892013-03-15 17:06:52 -0500823 hci_req_init(&req, hdev);
824
Johan Hedberg7d785252011-12-15 00:47:39 +0200825 hci_dev_lock(hdev);
826
Johan Hedberg890ea892013-03-15 17:06:52 -0500827 update_eir(&req);
828 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200829
830 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500831
832 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200833}
834
Johan Hedberg6a919082012-02-28 06:17:26 +0200835static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200836{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200837 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200838 return;
839
Johan Hedberg4f87da82012-03-02 19:55:56 +0200840 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200841
Johan Hedberg4f87da82012-03-02 19:55:56 +0200842 /* Non-mgmt controlled devices get this bit set
843 * implicitly so that pairing works for them, however
844 * for mgmt we require user-space to explicitly enable
845 * it
846 */
847 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200848}
849
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200850static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300851 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200852{
853 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200854
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200855 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200856
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300857 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200858
Johan Hedberg03811012010-12-08 00:21:06 +0200859 memset(&rp, 0, sizeof(rp));
860
Johan Hedberg03811012010-12-08 00:21:06 +0200861 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200862
863 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200864 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200865
866 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
867 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
868
869 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200870
871 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200872 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200873
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300874 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200875
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200876 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300877 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200878}
879
880static void mgmt_pending_free(struct pending_cmd *cmd)
881{
882 sock_put(cmd->sk);
883 kfree(cmd->param);
884 kfree(cmd);
885}
886
887static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300888 struct hci_dev *hdev, void *data,
889 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200890{
891 struct pending_cmd *cmd;
892
Andre Guedes12b94562012-06-07 19:05:45 -0300893 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200894 if (!cmd)
895 return NULL;
896
897 cmd->opcode = opcode;
898 cmd->index = hdev->id;
899
Andre Guedes12b94562012-06-07 19:05:45 -0300900 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200901 if (!cmd->param) {
902 kfree(cmd);
903 return NULL;
904 }
905
906 if (data)
907 memcpy(cmd->param, data, len);
908
909 cmd->sk = sk;
910 sock_hold(sk);
911
912 list_add(&cmd->list, &hdev->mgmt_pending);
913
914 return cmd;
915}
916
917static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300918 void (*cb)(struct pending_cmd *cmd,
919 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300920 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200921{
Andre Guedesa3d09352013-02-01 11:21:30 -0300922 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200923
Andre Guedesa3d09352013-02-01 11:21:30 -0300924 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200925 if (opcode > 0 && cmd->opcode != opcode)
926 continue;
927
928 cb(cmd, data);
929 }
930}
931
Johan Hedberg03811012010-12-08 00:21:06 +0200932static void mgmt_pending_remove(struct pending_cmd *cmd)
933{
934 list_del(&cmd->list);
935 mgmt_pending_free(cmd);
936}
937
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200938static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200939{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200940 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200941
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200942 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300943 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200944}
945
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200946static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300947 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200948{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300949 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200950 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200951 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200952
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200953 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200954
Johan Hedberga7e80f22013-01-09 16:05:19 +0200955 if (cp->val != 0x00 && cp->val != 0x01)
956 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
957 MGMT_STATUS_INVALID_PARAMS);
958
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300959 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200960
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300961 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
962 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
963 MGMT_STATUS_BUSY);
964 goto failed;
965 }
966
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100967 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
968 cancel_delayed_work(&hdev->power_off);
969
970 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200971 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
972 data, len);
973 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100974 goto failed;
975 }
976 }
977
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200978 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200979 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200980 goto failed;
981 }
982
Johan Hedberg03811012010-12-08 00:21:06 +0200983 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
984 if (!cmd) {
985 err = -ENOMEM;
986 goto failed;
987 }
988
989 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200990 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200991 else
Johan Hedberg19202572013-01-14 22:33:51 +0200992 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200993
994 err = 0;
995
996failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300997 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200998 return err;
999}
1000
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001001static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
1002 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001003{
1004 struct sk_buff *skb;
1005 struct mgmt_hdr *hdr;
1006
Andre Guedes790eff42012-06-07 19:05:46 -03001007 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001008 if (!skb)
1009 return -ENOMEM;
1010
1011 hdr = (void *) skb_put(skb, sizeof(*hdr));
1012 hdr->opcode = cpu_to_le16(event);
1013 if (hdev)
1014 hdr->index = cpu_to_le16(hdev->id);
1015 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05301016 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001017 hdr->len = cpu_to_le16(data_len);
1018
1019 if (data)
1020 memcpy(skb_put(skb, data_len), data, data_len);
1021
Marcel Holtmann97e0bde2012-02-22 13:49:28 +01001022 /* Time stamp */
1023 __net_timestamp(skb);
1024
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001025 hci_send_to_control(skb, skip_sk);
1026 kfree_skb(skb);
1027
1028 return 0;
1029}
1030
1031static int new_settings(struct hci_dev *hdev, struct sock *skip)
1032{
1033 __le32 ev;
1034
1035 ev = cpu_to_le32(get_current_settings(hdev));
1036
1037 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1038}
1039
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001040struct cmd_lookup {
1041 struct sock *sk;
1042 struct hci_dev *hdev;
1043 u8 mgmt_status;
1044};
1045
1046static void settings_rsp(struct pending_cmd *cmd, void *data)
1047{
1048 struct cmd_lookup *match = data;
1049
1050 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1051
1052 list_del(&cmd->list);
1053
1054 if (match->sk == NULL) {
1055 match->sk = cmd->sk;
1056 sock_hold(match->sk);
1057 }
1058
1059 mgmt_pending_free(cmd);
1060}
1061
1062static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1063{
1064 u8 *status = data;
1065
1066 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1067 mgmt_pending_remove(cmd);
1068}
1069
Johan Hedberge6fe7982013-10-02 15:45:22 +03001070static u8 mgmt_bredr_support(struct hci_dev *hdev)
1071{
1072 if (!lmp_bredr_capable(hdev))
1073 return MGMT_STATUS_NOT_SUPPORTED;
1074 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1075 return MGMT_STATUS_REJECTED;
1076 else
1077 return MGMT_STATUS_SUCCESS;
1078}
1079
1080static u8 mgmt_le_support(struct hci_dev *hdev)
1081{
1082 if (!lmp_le_capable(hdev))
1083 return MGMT_STATUS_NOT_SUPPORTED;
1084 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1085 return MGMT_STATUS_REJECTED;
1086 else
1087 return MGMT_STATUS_SUCCESS;
1088}
1089
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001090static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1091{
1092 struct pending_cmd *cmd;
1093 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001094 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001095 bool changed;
1096
1097 BT_DBG("status 0x%02x", status);
1098
1099 hci_dev_lock(hdev);
1100
1101 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1102 if (!cmd)
1103 goto unlock;
1104
1105 if (status) {
1106 u8 mgmt_err = mgmt_status(status);
1107 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001108 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001109 goto remove_cmd;
1110 }
1111
1112 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001113 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001114 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1115 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001116
1117 if (hdev->discov_timeout > 0) {
1118 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1119 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1120 to);
1121 }
1122 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001123 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1124 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001125 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001126
1127 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1128
1129 if (changed)
1130 new_settings(hdev, cmd->sk);
1131
Marcel Holtmann970ba522013-10-15 06:33:57 -07001132 /* When the discoverable mode gets changed, make sure
1133 * that class of device has the limited discoverable
1134 * bit correctly set.
1135 */
1136 hci_req_init(&req, hdev);
1137 update_class(&req);
1138 hci_req_run(&req, NULL);
1139
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001140remove_cmd:
1141 mgmt_pending_remove(cmd);
1142
1143unlock:
1144 hci_dev_unlock(hdev);
1145}
1146
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001147static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001148 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001149{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001150 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001151 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001152 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001153 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001154 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001155 int err;
1156
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001157 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001158
Johan Hedberg9a43e252013-10-20 19:00:07 +03001159 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1160 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001161 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberg9a43e252013-10-20 19:00:07 +03001162 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001163
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001164 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga7e80f22013-01-09 16:05:19 +02001165 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1166 MGMT_STATUS_INVALID_PARAMS);
1167
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001168 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001169
1170 /* Disabling discoverable requires that no timeout is set,
1171 * and enabling limited discoverable requires a timeout.
1172 */
1173 if ((cp->val == 0x00 && timeout > 0) ||
1174 (cp->val == 0x02 && timeout == 0))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001175 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001176 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001177
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001178 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001179
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001180 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001181 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001182 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001183 goto failed;
1184 }
1185
1186 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001187 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001188 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001189 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001190 goto failed;
1191 }
1192
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001193 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001194 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001195 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001196 goto failed;
1197 }
1198
1199 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001200 bool changed = false;
1201
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001202 /* Setting limited discoverable when powered off is
1203 * not a valid operation since it requires a timeout
1204 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1205 */
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001206 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1207 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1208 changed = true;
1209 }
1210
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001211 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001212 if (err < 0)
1213 goto failed;
1214
1215 if (changed)
1216 err = new_settings(hdev, sk);
1217
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001218 goto failed;
1219 }
1220
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001221 /* If the current mode is the same, then just update the timeout
1222 * value with the new value. And if only the timeout gets updated,
1223 * then no need for any HCI transactions.
1224 */
1225 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) &&
1226 (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE,
1227 &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001228 cancel_delayed_work(&hdev->discov_off);
1229 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001230
Marcel Holtmann36261542013-10-15 08:28:51 -07001231 if (cp->val && hdev->discov_timeout > 0) {
1232 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001233 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001234 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001235 }
1236
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001237 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001238 goto failed;
1239 }
1240
1241 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1242 if (!cmd) {
1243 err = -ENOMEM;
1244 goto failed;
1245 }
1246
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001247 /* Cancel any potential discoverable timeout that might be
1248 * still active and store new timeout value. The arming of
1249 * the timeout happens in the complete handler.
1250 */
1251 cancel_delayed_work(&hdev->discov_off);
1252 hdev->discov_timeout = timeout;
1253
Johan Hedbergb456f872013-10-19 23:38:22 +03001254 /* Limited discoverable mode */
1255 if (cp->val == 0x02)
1256 set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1257 else
1258 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1259
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001260 hci_req_init(&req, hdev);
1261
Johan Hedberg9a43e252013-10-20 19:00:07 +03001262 /* The procedure for LE-only controllers is much simpler - just
1263 * update the advertising data.
1264 */
1265 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1266 goto update_ad;
1267
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001268 scan = SCAN_PAGE;
1269
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001270 if (cp->val) {
1271 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001272
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001273 if (cp->val == 0x02) {
1274 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001275 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001276 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1277 hci_cp.iac_lap[1] = 0x8b;
1278 hci_cp.iac_lap[2] = 0x9e;
1279 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1280 hci_cp.iac_lap[4] = 0x8b;
1281 hci_cp.iac_lap[5] = 0x9e;
1282 } else {
1283 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001284 hci_cp.num_iac = 1;
1285 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1286 hci_cp.iac_lap[1] = 0x8b;
1287 hci_cp.iac_lap[2] = 0x9e;
1288 }
1289
1290 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1291 (hci_cp.num_iac * 3) + 1, &hci_cp);
1292
1293 scan |= SCAN_INQUIRY;
1294 } else {
1295 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1296 }
1297
1298 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001299
Johan Hedberg9a43e252013-10-20 19:00:07 +03001300update_ad:
1301 update_adv_data(&req);
1302
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001303 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001304 if (err < 0)
1305 mgmt_pending_remove(cmd);
1306
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001307failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001308 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001309 return err;
1310}
1311
Johan Hedberg406d7802013-03-15 17:07:09 -05001312static void write_fast_connectable(struct hci_request *req, bool enable)
1313{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001314 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001315 struct hci_cp_write_page_scan_activity acp;
1316 u8 type;
1317
Johan Hedberg547003b2013-10-21 16:51:53 +03001318 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1319 return;
1320
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001321 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1322 return;
1323
Johan Hedberg406d7802013-03-15 17:07:09 -05001324 if (enable) {
1325 type = PAGE_SCAN_TYPE_INTERLACED;
1326
1327 /* 160 msec page scan interval */
1328 acp.interval = __constant_cpu_to_le16(0x0100);
1329 } else {
1330 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1331
1332 /* default 1.28 sec page scan */
1333 acp.interval = __constant_cpu_to_le16(0x0800);
1334 }
1335
1336 acp.window = __constant_cpu_to_le16(0x0012);
1337
Johan Hedbergbd98b992013-03-15 17:07:13 -05001338 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1339 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1340 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1341 sizeof(acp), &acp);
1342
1343 if (hdev->page_scan_type != type)
1344 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001345}
1346
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001347static u8 get_adv_type(struct hci_dev *hdev)
1348{
1349 struct pending_cmd *cmd;
1350 bool connectable;
1351
1352 /* If there's a pending mgmt command the flag will not yet have
1353 * it's final value, so check for this first.
1354 */
1355 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1356 if (cmd) {
1357 struct mgmt_mode *cp = cmd->param;
1358 connectable = !!cp->val;
1359 } else {
1360 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1361 }
1362
1363 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1364}
1365
Johan Hedberg95c66e72013-10-14 16:20:06 +03001366static void enable_advertising(struct hci_request *req)
1367{
1368 struct hci_dev *hdev = req->hdev;
1369 struct hci_cp_le_set_adv_param cp;
1370 u8 enable = 0x01;
1371
1372 memset(&cp, 0, sizeof(cp));
1373 cp.min_interval = __constant_cpu_to_le16(0x0800);
1374 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001375 cp.type = get_adv_type(hdev);
Marcel Holtmann79830f62013-10-18 16:38:09 -07001376 cp.own_address_type = hdev->own_addr_type;
Johan Hedberg95c66e72013-10-14 16:20:06 +03001377 cp.channel_map = 0x07;
1378
1379 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1380
1381 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1382}
1383
1384static void disable_advertising(struct hci_request *req)
1385{
1386 u8 enable = 0x00;
1387
1388 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1389}
1390
Johan Hedberg2b76f452013-03-15 17:07:04 -05001391static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1392{
1393 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001394 struct mgmt_mode *cp;
1395 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001396
1397 BT_DBG("status 0x%02x", status);
1398
1399 hci_dev_lock(hdev);
1400
1401 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1402 if (!cmd)
1403 goto unlock;
1404
Johan Hedberg37438c12013-10-14 16:20:05 +03001405 if (status) {
1406 u8 mgmt_err = mgmt_status(status);
1407 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1408 goto remove_cmd;
1409 }
1410
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001411 cp = cmd->param;
1412 if (cp->val)
1413 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1414 else
1415 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1416
Johan Hedberg2b76f452013-03-15 17:07:04 -05001417 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1418
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001419 if (changed)
1420 new_settings(hdev, cmd->sk);
1421
Johan Hedberg37438c12013-10-14 16:20:05 +03001422remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001423 mgmt_pending_remove(cmd);
1424
1425unlock:
1426 hci_dev_unlock(hdev);
1427}
1428
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001429static int set_connectable_update_settings(struct hci_dev *hdev,
1430 struct sock *sk, u8 val)
1431{
1432 bool changed = false;
1433 int err;
1434
1435 if (!!val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1436 changed = true;
1437
1438 if (val) {
1439 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1440 } else {
1441 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1442 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1443 }
1444
1445 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1446 if (err < 0)
1447 return err;
1448
1449 if (changed)
1450 return new_settings(hdev, sk);
1451
1452 return 0;
1453}
1454
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001455static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001456 u16 len)
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001457{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001458 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001459 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001460 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001461 u8 scan;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001462 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001463
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001464 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001465
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001466 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1467 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001468 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001469 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001470
Johan Hedberga7e80f22013-01-09 16:05:19 +02001471 if (cp->val != 0x00 && cp->val != 0x01)
1472 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1473 MGMT_STATUS_INVALID_PARAMS);
1474
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001475 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001476
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001477 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001478 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001479 goto failed;
1480 }
1481
1482 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001483 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001484 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001485 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001486 goto failed;
1487 }
1488
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001489 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1490 if (!cmd) {
1491 err = -ENOMEM;
1492 goto failed;
1493 }
1494
Johan Hedberg2b76f452013-03-15 17:07:04 -05001495 hci_req_init(&req, hdev);
1496
Johan Hedberg9a43e252013-10-20 19:00:07 +03001497 /* If BR/EDR is not enabled and we disable advertising as a
1498 * by-product of disabling connectable, we need to update the
1499 * advertising flags.
1500 */
1501 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
1502 if (!cp->val) {
1503 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1504 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1505 }
1506 update_adv_data(&req);
1507 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001508 if (cp->val) {
1509 scan = SCAN_PAGE;
1510 } else {
1511 scan = 0;
1512
1513 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001514 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001515 cancel_delayed_work(&hdev->discov_off);
1516 }
1517
1518 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1519 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001520
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001521 /* If we're going from non-connectable to connectable or
1522 * vice-versa when fast connectable is enabled ensure that fast
1523 * connectable gets disabled. write_fast_connectable won't do
1524 * anything if the page scan parameters are already what they
1525 * should be.
1526 */
1527 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001528 write_fast_connectable(&req, false);
1529
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001530 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1531 hci_conn_num(hdev, LE_LINK) == 0) {
1532 disable_advertising(&req);
1533 enable_advertising(&req);
1534 }
1535
Johan Hedberg2b76f452013-03-15 17:07:04 -05001536 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001537 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001538 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001539 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03001540 err = set_connectable_update_settings(hdev, sk,
1541 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03001542 goto failed;
1543 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001544
1545failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001546 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001547 return err;
1548}
1549
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001550static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001551 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001552{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001553 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001554 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001555 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001556
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001557 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001558
Johan Hedberga7e80f22013-01-09 16:05:19 +02001559 if (cp->val != 0x00 && cp->val != 0x01)
1560 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1561 MGMT_STATUS_INVALID_PARAMS);
1562
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001563 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001564
1565 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001566 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001567 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001568 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001569
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001570 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001571 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001572 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001573
Marcel Holtmann55594352013-10-06 16:11:57 -07001574 if (changed)
1575 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001576
Marcel Holtmann55594352013-10-06 16:11:57 -07001577unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001578 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001579 return err;
1580}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001581
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001582static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1583 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001584{
1585 struct mgmt_mode *cp = data;
1586 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001587 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001588 int err;
1589
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001590 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001591
Johan Hedberge6fe7982013-10-02 15:45:22 +03001592 status = mgmt_bredr_support(hdev);
1593 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001594 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001595 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001596
Johan Hedberga7e80f22013-01-09 16:05:19 +02001597 if (cp->val != 0x00 && cp->val != 0x01)
1598 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1599 MGMT_STATUS_INVALID_PARAMS);
1600
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001601 hci_dev_lock(hdev);
1602
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001603 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001604 bool changed = false;
1605
1606 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001607 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001608 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1609 changed = true;
1610 }
1611
1612 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1613 if (err < 0)
1614 goto failed;
1615
1616 if (changed)
1617 err = new_settings(hdev, sk);
1618
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001619 goto failed;
1620 }
1621
1622 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001623 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001624 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001625 goto failed;
1626 }
1627
1628 val = !!cp->val;
1629
1630 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1631 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1632 goto failed;
1633 }
1634
1635 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1636 if (!cmd) {
1637 err = -ENOMEM;
1638 goto failed;
1639 }
1640
1641 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1642 if (err < 0) {
1643 mgmt_pending_remove(cmd);
1644 goto failed;
1645 }
1646
1647failed:
1648 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001649 return err;
1650}
1651
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001652static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001653{
1654 struct mgmt_mode *cp = data;
1655 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001656 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001657 int err;
1658
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001659 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001660
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001661 status = mgmt_bredr_support(hdev);
1662 if (status)
1663 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1664
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001665 if (!lmp_ssp_capable(hdev))
1666 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1667 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001668
Johan Hedberga7e80f22013-01-09 16:05:19 +02001669 if (cp->val != 0x00 && cp->val != 0x01)
1670 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1671 MGMT_STATUS_INVALID_PARAMS);
1672
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001673 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001674
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001675 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001676 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001677
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001678 if (cp->val) {
1679 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1680 &hdev->dev_flags);
1681 } else {
1682 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1683 &hdev->dev_flags);
1684 if (!changed)
1685 changed = test_and_clear_bit(HCI_HS_ENABLED,
1686 &hdev->dev_flags);
1687 else
1688 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001689 }
1690
1691 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1692 if (err < 0)
1693 goto failed;
1694
1695 if (changed)
1696 err = new_settings(hdev, sk);
1697
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001698 goto failed;
1699 }
1700
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001701 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1702 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001703 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1704 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001705 goto failed;
1706 }
1707
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001708 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001709 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1710 goto failed;
1711 }
1712
1713 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1714 if (!cmd) {
1715 err = -ENOMEM;
1716 goto failed;
1717 }
1718
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001719 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001720 if (err < 0) {
1721 mgmt_pending_remove(cmd);
1722 goto failed;
1723 }
1724
1725failed:
1726 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001727 return err;
1728}
1729
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001730static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001731{
1732 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001733 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001734 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001735 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001736
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001737 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001738
Johan Hedberge6fe7982013-10-02 15:45:22 +03001739 status = mgmt_bredr_support(hdev);
1740 if (status)
1741 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001742
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001743 if (!lmp_ssp_capable(hdev))
1744 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1745 MGMT_STATUS_NOT_SUPPORTED);
1746
1747 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1748 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1749 MGMT_STATUS_REJECTED);
1750
Johan Hedberga7e80f22013-01-09 16:05:19 +02001751 if (cp->val != 0x00 && cp->val != 0x01)
1752 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1753 MGMT_STATUS_INVALID_PARAMS);
1754
Marcel Holtmannee392692013-10-01 22:59:23 -07001755 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001756
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001757 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001758 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001759 } else {
1760 if (hdev_is_powered(hdev)) {
1761 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1762 MGMT_STATUS_REJECTED);
1763 goto unlock;
1764 }
1765
Marcel Holtmannee392692013-10-01 22:59:23 -07001766 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001767 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001768
1769 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1770 if (err < 0)
1771 goto unlock;
1772
1773 if (changed)
1774 err = new_settings(hdev, sk);
1775
1776unlock:
1777 hci_dev_unlock(hdev);
1778 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001779}
1780
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001781static void le_enable_complete(struct hci_dev *hdev, u8 status)
1782{
1783 struct cmd_lookup match = { NULL, hdev };
1784
1785 if (status) {
1786 u8 mgmt_err = mgmt_status(status);
1787
1788 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1789 &mgmt_err);
1790 return;
1791 }
1792
1793 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1794
1795 new_settings(hdev, match.sk);
1796
1797 if (match.sk)
1798 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001799
1800 /* Make sure the controller has a good default for
1801 * advertising data. Restrict the update to when LE
1802 * has actually been enabled. During power on, the
1803 * update in powered_update_hci will take care of it.
1804 */
1805 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1806 struct hci_request req;
1807
1808 hci_dev_lock(hdev);
1809
1810 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001811 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07001812 update_scan_rsp_data(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001813 hci_req_run(&req, NULL);
1814
1815 hci_dev_unlock(hdev);
1816 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001817}
1818
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001819static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001820{
1821 struct mgmt_mode *cp = data;
1822 struct hci_cp_write_le_host_supported hci_cp;
1823 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001824 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001825 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001826 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001827
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001828 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001829
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001830 if (!lmp_le_capable(hdev))
1831 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1832 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001833
Johan Hedberga7e80f22013-01-09 16:05:19 +02001834 if (cp->val != 0x00 && cp->val != 0x01)
1835 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1836 MGMT_STATUS_INVALID_PARAMS);
1837
Johan Hedbergc73eee92013-04-19 18:35:21 +03001838 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001839 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001840 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1841 MGMT_STATUS_REJECTED);
1842
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001843 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001844
1845 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001846 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001847
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001848 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001849 bool changed = false;
1850
1851 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1852 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1853 changed = true;
1854 }
1855
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001856 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1857 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001858 changed = true;
1859 }
1860
Johan Hedberg06199cf2012-02-22 16:37:11 +02001861 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1862 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001863 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001864
1865 if (changed)
1866 err = new_settings(hdev, sk);
1867
Johan Hedberg1de028c2012-02-29 19:55:35 -08001868 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001869 }
1870
Johan Hedberg4375f102013-09-25 13:26:10 +03001871 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1872 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001873 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001874 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001875 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001876 }
1877
1878 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1879 if (!cmd) {
1880 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001881 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001882 }
1883
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001884 hci_req_init(&req, hdev);
1885
Johan Hedberg06199cf2012-02-22 16:37:11 +02001886 memset(&hci_cp, 0, sizeof(hci_cp));
1887
1888 if (val) {
1889 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001890 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001891 } else {
1892 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1893 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001894 }
1895
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001896 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1897 &hci_cp);
1898
1899 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301900 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001901 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001902
Johan Hedberg1de028c2012-02-29 19:55:35 -08001903unlock:
1904 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001905 return err;
1906}
1907
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001908/* This is a helper function to test for pending mgmt commands that can
1909 * cause CoD or EIR HCI commands. We can only allow one such pending
1910 * mgmt command at a time since otherwise we cannot easily track what
1911 * the current values are, will be, and based on that calculate if a new
1912 * HCI command needs to be sent and if yes with what value.
1913 */
1914static bool pending_eir_or_class(struct hci_dev *hdev)
1915{
1916 struct pending_cmd *cmd;
1917
1918 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1919 switch (cmd->opcode) {
1920 case MGMT_OP_ADD_UUID:
1921 case MGMT_OP_REMOVE_UUID:
1922 case MGMT_OP_SET_DEV_CLASS:
1923 case MGMT_OP_SET_POWERED:
1924 return true;
1925 }
1926 }
1927
1928 return false;
1929}
1930
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001931static const u8 bluetooth_base_uuid[] = {
1932 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1933 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1934};
1935
1936static u8 get_uuid_size(const u8 *uuid)
1937{
1938 u32 val;
1939
1940 if (memcmp(uuid, bluetooth_base_uuid, 12))
1941 return 128;
1942
1943 val = get_unaligned_le32(&uuid[12]);
1944 if (val > 0xffff)
1945 return 32;
1946
1947 return 16;
1948}
1949
Johan Hedberg92da6092013-03-15 17:06:55 -05001950static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1951{
1952 struct pending_cmd *cmd;
1953
1954 hci_dev_lock(hdev);
1955
1956 cmd = mgmt_pending_find(mgmt_op, hdev);
1957 if (!cmd)
1958 goto unlock;
1959
1960 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1961 hdev->dev_class, 3);
1962
1963 mgmt_pending_remove(cmd);
1964
1965unlock:
1966 hci_dev_unlock(hdev);
1967}
1968
1969static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1970{
1971 BT_DBG("status 0x%02x", status);
1972
1973 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1974}
1975
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001976static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001977{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001978 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001979 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001980 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001981 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001982 int err;
1983
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001984 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001985
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001986 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001987
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001988 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001989 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001990 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001991 goto failed;
1992 }
1993
Andre Guedes92c4c202012-06-07 19:05:44 -03001994 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001995 if (!uuid) {
1996 err = -ENOMEM;
1997 goto failed;
1998 }
1999
2000 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002001 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002002 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002003
Johan Hedbergde66aa62013-01-27 00:31:27 +02002004 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002005
Johan Hedberg890ea892013-03-15 17:06:52 -05002006 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002007
Johan Hedberg890ea892013-03-15 17:06:52 -05002008 update_class(&req);
2009 update_eir(&req);
2010
Johan Hedberg92da6092013-03-15 17:06:55 -05002011 err = hci_req_run(&req, add_uuid_complete);
2012 if (err < 0) {
2013 if (err != -ENODATA)
2014 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002015
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002016 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002017 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002018 goto failed;
2019 }
2020
2021 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002022 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002023 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002024 goto failed;
2025 }
2026
2027 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002028
2029failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002030 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002031 return err;
2032}
2033
Johan Hedberg24b78d02012-02-23 23:24:30 +02002034static bool enable_service_cache(struct hci_dev *hdev)
2035{
2036 if (!hdev_is_powered(hdev))
2037 return false;
2038
2039 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002040 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2041 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002042 return true;
2043 }
2044
2045 return false;
2046}
2047
Johan Hedberg92da6092013-03-15 17:06:55 -05002048static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
2049{
2050 BT_DBG("status 0x%02x", status);
2051
2052 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2053}
2054
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002055static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002056 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002057{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002058 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002059 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002060 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002061 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 -05002062 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002063 int err, found;
2064
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002065 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002066
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002067 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002068
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002069 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002070 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002071 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002072 goto unlock;
2073 }
2074
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002075 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
2076 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002077
Johan Hedberg24b78d02012-02-23 23:24:30 +02002078 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002079 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002080 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002081 goto unlock;
2082 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002083
Johan Hedberg9246a862012-02-23 21:33:16 +02002084 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002085 }
2086
2087 found = 0;
2088
Johan Hedberg056341c2013-01-27 00:31:30 +02002089 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002090 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2091 continue;
2092
2093 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002094 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002095 found++;
2096 }
2097
2098 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002099 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002100 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002101 goto unlock;
2102 }
2103
Johan Hedberg9246a862012-02-23 21:33:16 +02002104update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002105 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002106
Johan Hedberg890ea892013-03-15 17:06:52 -05002107 update_class(&req);
2108 update_eir(&req);
2109
Johan Hedberg92da6092013-03-15 17:06:55 -05002110 err = hci_req_run(&req, remove_uuid_complete);
2111 if (err < 0) {
2112 if (err != -ENODATA)
2113 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002114
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002115 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002116 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002117 goto unlock;
2118 }
2119
2120 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002121 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002122 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002123 goto unlock;
2124 }
2125
2126 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002127
2128unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002129 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002130 return err;
2131}
2132
Johan Hedberg92da6092013-03-15 17:06:55 -05002133static void set_class_complete(struct hci_dev *hdev, u8 status)
2134{
2135 BT_DBG("status 0x%02x", status);
2136
2137 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2138}
2139
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002140static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002141 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002142{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002143 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002144 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002145 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002146 int err;
2147
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002148 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002149
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002150 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002151 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2152 MGMT_STATUS_NOT_SUPPORTED);
2153
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002154 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002155
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002156 if (pending_eir_or_class(hdev)) {
2157 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2158 MGMT_STATUS_BUSY);
2159 goto unlock;
2160 }
2161
2162 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2163 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2164 MGMT_STATUS_INVALID_PARAMS);
2165 goto unlock;
2166 }
2167
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002168 hdev->major_class = cp->major;
2169 hdev->minor_class = cp->minor;
2170
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002171 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002172 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002173 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002174 goto unlock;
2175 }
2176
Johan Hedberg890ea892013-03-15 17:06:52 -05002177 hci_req_init(&req, hdev);
2178
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002179 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002180 hci_dev_unlock(hdev);
2181 cancel_delayed_work_sync(&hdev->service_cache);
2182 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002183 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002184 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002185
Johan Hedberg890ea892013-03-15 17:06:52 -05002186 update_class(&req);
2187
Johan Hedberg92da6092013-03-15 17:06:55 -05002188 err = hci_req_run(&req, set_class_complete);
2189 if (err < 0) {
2190 if (err != -ENODATA)
2191 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002192
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002193 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002194 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002195 goto unlock;
2196 }
2197
2198 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002199 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002200 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002201 goto unlock;
2202 }
2203
2204 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002205
Johan Hedbergb5235a62012-02-21 14:32:24 +02002206unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002207 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002208 return err;
2209}
2210
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002211static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002212 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002213{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002214 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002215 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002216 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002217
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002218 BT_DBG("request for %s", hdev->name);
2219
2220 if (!lmp_bredr_capable(hdev))
2221 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2222 MGMT_STATUS_NOT_SUPPORTED);
2223
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002224 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002225
Johan Hedberg86742e12011-11-07 23:13:38 +02002226 expected_len = sizeof(*cp) + key_count *
2227 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002228 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002229 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002230 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002231 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002232 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002233 }
2234
Johan Hedberg4ae14302013-01-20 14:27:13 +02002235 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2236 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2237 MGMT_STATUS_INVALID_PARAMS);
2238
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002239 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002240 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002241
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002242 for (i = 0; i < key_count; i++) {
2243 struct mgmt_link_key_info *key = &cp->keys[i];
2244
Marcel Holtmann8e991132014-01-10 02:07:25 -08002245 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002246 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2247 MGMT_STATUS_INVALID_PARAMS);
2248 }
2249
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002250 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002251
2252 hci_link_keys_clear(hdev);
2253
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002254 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002255 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002256 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002257 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002258
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002259 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002260 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002261
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002262 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002263 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002264 }
2265
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002266 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002267
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002268 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002269
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002270 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002271}
2272
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002273static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002274 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002275{
2276 struct mgmt_ev_device_unpaired ev;
2277
2278 bacpy(&ev.addr.bdaddr, bdaddr);
2279 ev.addr.type = addr_type;
2280
2281 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002282 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002283}
2284
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002285static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002286 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002287{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002288 struct mgmt_cp_unpair_device *cp = data;
2289 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002290 struct hci_cp_disconnect dc;
2291 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002292 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002293 int err;
2294
Johan Hedberga8a1d192011-11-10 15:54:38 +02002295 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002296 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2297 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002298
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002299 if (!bdaddr_type_is_valid(cp->addr.type))
2300 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2301 MGMT_STATUS_INVALID_PARAMS,
2302 &rp, sizeof(rp));
2303
Johan Hedberg118da702013-01-20 14:27:20 +02002304 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2305 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2306 MGMT_STATUS_INVALID_PARAMS,
2307 &rp, sizeof(rp));
2308
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002309 hci_dev_lock(hdev);
2310
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002311 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002312 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002313 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002314 goto unlock;
2315 }
2316
Andre Guedes591f47f2012-04-24 21:02:49 -03002317 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02002318 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
2319 else
2320 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002321
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002322 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002323 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002324 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002325 goto unlock;
2326 }
2327
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002328 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002329 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002330 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002331 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002332 else
2333 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002334 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002335 } else {
2336 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002337 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002338
Johan Hedberga8a1d192011-11-10 15:54:38 +02002339 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002340 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002341 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002342 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002343 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002344 }
2345
Johan Hedberg124f6e32012-02-09 13:50:12 +02002346 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002347 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002348 if (!cmd) {
2349 err = -ENOMEM;
2350 goto unlock;
2351 }
2352
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002353 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002354 dc.reason = 0x13; /* Remote User Terminated Connection */
2355 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2356 if (err < 0)
2357 mgmt_pending_remove(cmd);
2358
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002359unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002360 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002361 return err;
2362}
2363
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002364static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002365 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002366{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002367 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002368 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002369 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002370 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002371 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002372 int err;
2373
2374 BT_DBG("");
2375
Johan Hedberg06a63b12013-01-20 14:27:21 +02002376 memset(&rp, 0, sizeof(rp));
2377 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2378 rp.addr.type = cp->addr.type;
2379
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002380 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002381 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2382 MGMT_STATUS_INVALID_PARAMS,
2383 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002384
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002385 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002386
2387 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002388 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2389 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002390 goto failed;
2391 }
2392
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002393 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002394 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2395 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002396 goto failed;
2397 }
2398
Andre Guedes591f47f2012-04-24 21:02:49 -03002399 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002400 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2401 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002402 else
2403 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002404
Vishal Agarwalf9607272012-06-13 05:32:43 +05302405 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002406 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2407 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002408 goto failed;
2409 }
2410
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002411 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002412 if (!cmd) {
2413 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002414 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002415 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002416
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002417 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002418 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002419
2420 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2421 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002422 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002423
2424failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002425 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002426 return err;
2427}
2428
Andre Guedes57c14772012-04-24 21:02:50 -03002429static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002430{
2431 switch (link_type) {
2432 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002433 switch (addr_type) {
2434 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002435 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002436
Johan Hedberg48264f02011-11-09 13:58:58 +02002437 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002438 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002439 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002440 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002441
Johan Hedberg4c659c32011-11-07 23:13:39 +02002442 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002443 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002444 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002445 }
2446}
2447
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002448static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2449 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002450{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002451 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002452 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002453 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002454 int err;
2455 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002456
2457 BT_DBG("");
2458
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002459 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002460
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002461 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002462 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002463 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002464 goto unlock;
2465 }
2466
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002467 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002468 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2469 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002470 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002471 }
2472
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002473 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002474 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002475 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002476 err = -ENOMEM;
2477 goto unlock;
2478 }
2479
Johan Hedberg2784eb42011-01-21 13:56:35 +02002480 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002481 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002482 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2483 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002484 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002485 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002486 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002487 continue;
2488 i++;
2489 }
2490
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002491 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002492
Johan Hedberg4c659c32011-11-07 23:13:39 +02002493 /* Recalculate length in case of filtered SCO connections, etc */
2494 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002496 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002497 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002498
Johan Hedberga38528f2011-01-22 06:46:43 +02002499 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002500
2501unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002502 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002503 return err;
2504}
2505
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002506static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002507 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002508{
2509 struct pending_cmd *cmd;
2510 int err;
2511
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002512 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002513 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002514 if (!cmd)
2515 return -ENOMEM;
2516
Johan Hedbergd8457692012-02-17 14:24:57 +02002517 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002518 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002519 if (err < 0)
2520 mgmt_pending_remove(cmd);
2521
2522 return err;
2523}
2524
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002525static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002526 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002527{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002528 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002529 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002530 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002531 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002532 int err;
2533
2534 BT_DBG("");
2535
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002536 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002537
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002538 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002539 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002540 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002541 goto failed;
2542 }
2543
Johan Hedbergd8457692012-02-17 14:24:57 +02002544 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002545 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002546 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002547 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002548 goto failed;
2549 }
2550
2551 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002552 struct mgmt_cp_pin_code_neg_reply ncp;
2553
2554 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002555
2556 BT_ERR("PIN code is not 16 bytes long");
2557
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002558 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002559 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002560 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002561 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002562
2563 goto failed;
2564 }
2565
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002566 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002567 if (!cmd) {
2568 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002569 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002570 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002571
Johan Hedbergd8457692012-02-17 14:24:57 +02002572 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002573 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002574 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002575
2576 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2577 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002578 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002579
2580failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002581 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002582 return err;
2583}
2584
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002585static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2586 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002587{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002588 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002589
2590 BT_DBG("");
2591
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002592 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002593
2594 hdev->io_capability = cp->io_capability;
2595
2596 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002597 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002598
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002599 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002600
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002601 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2602 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002603}
2604
Gustavo Padovan6039aa732012-05-23 04:04:18 -03002605static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002606{
2607 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002608 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002609
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002610 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002611 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2612 continue;
2613
Johan Hedberge9a416b2011-02-19 12:05:56 -03002614 if (cmd->user_data != conn)
2615 continue;
2616
2617 return cmd;
2618 }
2619
2620 return NULL;
2621}
2622
2623static void pairing_complete(struct pending_cmd *cmd, u8 status)
2624{
2625 struct mgmt_rp_pair_device rp;
2626 struct hci_conn *conn = cmd->user_data;
2627
Johan Hedbergba4e5642011-11-11 00:07:34 +02002628 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002629 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002630
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002631 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002632 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002633
2634 /* So we don't get further callbacks for this connection */
2635 conn->connect_cfm_cb = NULL;
2636 conn->security_cfm_cb = NULL;
2637 conn->disconn_cfm_cb = NULL;
2638
David Herrmann76a68ba2013-04-06 20:28:37 +02002639 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002640
Johan Hedberga664b5b2011-02-19 12:06:02 -03002641 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002642}
2643
2644static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2645{
2646 struct pending_cmd *cmd;
2647
2648 BT_DBG("status %u", status);
2649
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002650 cmd = find_pairing(conn);
2651 if (!cmd)
2652 BT_DBG("Unable to find a pending command");
2653 else
Johan Hedberge2113262012-02-18 15:20:03 +02002654 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002655}
2656
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302657static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2658{
2659 struct pending_cmd *cmd;
2660
2661 BT_DBG("status %u", status);
2662
2663 if (!status)
2664 return;
2665
2666 cmd = find_pairing(conn);
2667 if (!cmd)
2668 BT_DBG("Unable to find a pending command");
2669 else
2670 pairing_complete(cmd, mgmt_status(status));
2671}
2672
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002673static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002674 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002675{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002676 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002677 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002678 struct pending_cmd *cmd;
2679 u8 sec_level, auth_type;
2680 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002681 int err;
2682
2683 BT_DBG("");
2684
Szymon Jancf950a30e2013-01-18 12:48:07 +01002685 memset(&rp, 0, sizeof(rp));
2686 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2687 rp.addr.type = cp->addr.type;
2688
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002689 if (!bdaddr_type_is_valid(cp->addr.type))
2690 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2691 MGMT_STATUS_INVALID_PARAMS,
2692 &rp, sizeof(rp));
2693
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002694 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002695
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002696 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002697 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2698 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002699 goto unlock;
2700 }
2701
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002702 sec_level = BT_SECURITY_MEDIUM;
2703 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002704 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002705 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002706 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002707
Andre Guedes591f47f2012-04-24 21:02:49 -03002708 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002709 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2710 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002711 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002712 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2713 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002714
Ville Tervo30e76272011-02-22 16:10:53 -03002715 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002716 int status;
2717
2718 if (PTR_ERR(conn) == -EBUSY)
2719 status = MGMT_STATUS_BUSY;
2720 else
2721 status = MGMT_STATUS_CONNECT_FAILED;
2722
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002723 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002724 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002725 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002726 goto unlock;
2727 }
2728
2729 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002730 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002731 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002732 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002733 goto unlock;
2734 }
2735
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002736 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002737 if (!cmd) {
2738 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002739 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002740 goto unlock;
2741 }
2742
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002743 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002744 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002745 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302746 else
2747 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002748
Johan Hedberge9a416b2011-02-19 12:05:56 -03002749 conn->security_cfm_cb = pairing_complete_cb;
2750 conn->disconn_cfm_cb = pairing_complete_cb;
2751 conn->io_capability = cp->io_cap;
2752 cmd->user_data = conn;
2753
2754 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002755 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002756 pairing_complete(cmd, 0);
2757
2758 err = 0;
2759
2760unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002761 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002762 return err;
2763}
2764
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002765static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2766 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002767{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002768 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002769 struct pending_cmd *cmd;
2770 struct hci_conn *conn;
2771 int err;
2772
2773 BT_DBG("");
2774
Johan Hedberg28424702012-02-02 04:02:29 +02002775 hci_dev_lock(hdev);
2776
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002777 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002778 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002779 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002780 goto unlock;
2781 }
2782
Johan Hedberg28424702012-02-02 04:02:29 +02002783 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2784 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002785 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002786 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002787 goto unlock;
2788 }
2789
2790 conn = cmd->user_data;
2791
2792 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002793 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002794 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002795 goto unlock;
2796 }
2797
2798 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2799
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002800 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002801 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002802unlock:
2803 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002804 return err;
2805}
2806
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002807static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002808 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002809 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002810{
Johan Hedberga5c29682011-02-19 12:05:57 -03002811 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002812 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002813 int err;
2814
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002815 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002816
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002817 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002818 err = cmd_complete(sk, hdev->id, mgmt_op,
2819 MGMT_STATUS_NOT_POWERED, addr,
2820 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002821 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002822 }
2823
Johan Hedberg1707c602013-03-15 17:07:15 -05002824 if (addr->type == BDADDR_BREDR)
2825 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002826 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002827 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002828
Johan Hedberg272d90d2012-02-09 15:26:12 +02002829 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002830 err = cmd_complete(sk, hdev->id, mgmt_op,
2831 MGMT_STATUS_NOT_CONNECTED, addr,
2832 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002833 goto done;
2834 }
2835
Johan Hedberg1707c602013-03-15 17:07:15 -05002836 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002837 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002838 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002839
Brian Gix5fe57d92011-12-21 16:12:13 -08002840 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002841 err = cmd_complete(sk, hdev->id, mgmt_op,
2842 MGMT_STATUS_SUCCESS, addr,
2843 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002844 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002845 err = cmd_complete(sk, hdev->id, mgmt_op,
2846 MGMT_STATUS_FAILED, addr,
2847 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002848
Brian Gix47c15e22011-11-16 13:53:14 -08002849 goto done;
2850 }
2851
Johan Hedberg1707c602013-03-15 17:07:15 -05002852 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002853 if (!cmd) {
2854 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002855 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002856 }
2857
Brian Gix0df4c182011-11-16 13:53:13 -08002858 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002859 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2860 struct hci_cp_user_passkey_reply cp;
2861
Johan Hedberg1707c602013-03-15 17:07:15 -05002862 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002863 cp.passkey = passkey;
2864 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2865 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002866 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2867 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002868
Johan Hedberga664b5b2011-02-19 12:06:02 -03002869 if (err < 0)
2870 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002871
Brian Gix0df4c182011-11-16 13:53:13 -08002872done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002873 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002874 return err;
2875}
2876
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302877static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2878 void *data, u16 len)
2879{
2880 struct mgmt_cp_pin_code_neg_reply *cp = data;
2881
2882 BT_DBG("");
2883
Johan Hedberg1707c602013-03-15 17:07:15 -05002884 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302885 MGMT_OP_PIN_CODE_NEG_REPLY,
2886 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2887}
2888
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002889static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2890 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002891{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002892 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002893
2894 BT_DBG("");
2895
2896 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002897 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002898 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002899
Johan Hedberg1707c602013-03-15 17:07:15 -05002900 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002901 MGMT_OP_USER_CONFIRM_REPLY,
2902 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002903}
2904
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002905static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002906 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002907{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002908 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002909
2910 BT_DBG("");
2911
Johan Hedberg1707c602013-03-15 17:07:15 -05002912 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002913 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2914 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002915}
2916
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002917static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2918 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002919{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002920 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002921
2922 BT_DBG("");
2923
Johan Hedberg1707c602013-03-15 17:07:15 -05002924 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002925 MGMT_OP_USER_PASSKEY_REPLY,
2926 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002927}
2928
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002929static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002930 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002931{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002932 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002933
2934 BT_DBG("");
2935
Johan Hedberg1707c602013-03-15 17:07:15 -05002936 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002937 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2938 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002939}
2940
Johan Hedberg13928972013-03-15 17:07:00 -05002941static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002942{
Johan Hedberg13928972013-03-15 17:07:00 -05002943 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002944 struct hci_cp_write_local_name cp;
2945
Johan Hedberg13928972013-03-15 17:07:00 -05002946 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002947
Johan Hedberg890ea892013-03-15 17:06:52 -05002948 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002949}
2950
Johan Hedberg13928972013-03-15 17:07:00 -05002951static void set_name_complete(struct hci_dev *hdev, u8 status)
2952{
2953 struct mgmt_cp_set_local_name *cp;
2954 struct pending_cmd *cmd;
2955
2956 BT_DBG("status 0x%02x", status);
2957
2958 hci_dev_lock(hdev);
2959
2960 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2961 if (!cmd)
2962 goto unlock;
2963
2964 cp = cmd->param;
2965
2966 if (status)
2967 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2968 mgmt_status(status));
2969 else
2970 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2971 cp, sizeof(*cp));
2972
2973 mgmt_pending_remove(cmd);
2974
2975unlock:
2976 hci_dev_unlock(hdev);
2977}
2978
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002979static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002980 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002981{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002982 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002983 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002984 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002985 int err;
2986
2987 BT_DBG("");
2988
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002989 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002990
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002991 /* If the old values are the same as the new ones just return a
2992 * direct command complete event.
2993 */
2994 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2995 !memcmp(hdev->short_name, cp->short_name,
2996 sizeof(hdev->short_name))) {
2997 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2998 data, len);
2999 goto failed;
3000 }
3001
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003002 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003003
Johan Hedbergb5235a62012-02-21 14:32:24 +02003004 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003005 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003006
3007 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003008 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003009 if (err < 0)
3010 goto failed;
3011
3012 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003013 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003014
Johan Hedbergb5235a62012-02-21 14:32:24 +02003015 goto failed;
3016 }
3017
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003018 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003019 if (!cmd) {
3020 err = -ENOMEM;
3021 goto failed;
3022 }
3023
Johan Hedberg13928972013-03-15 17:07:00 -05003024 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3025
Johan Hedberg890ea892013-03-15 17:06:52 -05003026 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003027
3028 if (lmp_bredr_capable(hdev)) {
3029 update_name(&req);
3030 update_eir(&req);
3031 }
3032
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003033 /* The name is stored in the scan response data and so
3034 * no need to udpate the advertising data here.
3035 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003036 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003037 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003038
Johan Hedberg13928972013-03-15 17:07:00 -05003039 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003040 if (err < 0)
3041 mgmt_pending_remove(cmd);
3042
3043failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003044 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003045 return err;
3046}
3047
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003048static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003049 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003050{
Szymon Jancc35938b2011-03-22 13:12:21 +01003051 struct pending_cmd *cmd;
3052 int err;
3053
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003054 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003055
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003056 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003057
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003058 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003059 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003060 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003061 goto unlock;
3062 }
3063
Andre Guedes9a1a1992012-07-24 15:03:48 -03003064 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003065 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003066 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003067 goto unlock;
3068 }
3069
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003070 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003071 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003072 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003073 goto unlock;
3074 }
3075
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003076 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003077 if (!cmd) {
3078 err = -ENOMEM;
3079 goto unlock;
3080 }
3081
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003082 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
3083 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
3084 0, NULL);
3085 else
3086 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3087
Szymon Jancc35938b2011-03-22 13:12:21 +01003088 if (err < 0)
3089 mgmt_pending_remove(cmd);
3090
3091unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003092 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003093 return err;
3094}
3095
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003096static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003097 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003098{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003099 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003100 u8 status;
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
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003107 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003108 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01003109 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003110 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01003111 else
Szymon Janca6785be2012-12-13 15:11:21 +01003112 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003113
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003114 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003115 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003116
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003117 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003118 return err;
3119}
3120
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003121static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003122 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003123{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003124 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003125 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003126 int err;
3127
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003128 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003129
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003130 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003131
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003132 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003133 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003134 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003135 else
Szymon Janca6785be2012-12-13 15:11:21 +01003136 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003137
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003138 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003139 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003140
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003141 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003142 return err;
3143}
3144
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003145static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3146{
3147 struct pending_cmd *cmd;
3148 u8 type;
3149 int err;
3150
3151 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3152
3153 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3154 if (!cmd)
3155 return -ENOENT;
3156
3157 type = hdev->discovery.type;
3158
3159 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3160 &type, sizeof(type));
3161 mgmt_pending_remove(cmd);
3162
3163 return err;
3164}
3165
Andre Guedes7c307722013-04-30 15:29:28 -03003166static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3167{
3168 BT_DBG("status %d", status);
3169
3170 if (status) {
3171 hci_dev_lock(hdev);
3172 mgmt_start_discovery_failed(hdev, status);
3173 hci_dev_unlock(hdev);
3174 return;
3175 }
3176
3177 hci_dev_lock(hdev);
3178 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3179 hci_dev_unlock(hdev);
3180
3181 switch (hdev->discovery.type) {
3182 case DISCOV_TYPE_LE:
3183 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003184 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003185 break;
3186
3187 case DISCOV_TYPE_INTERLEAVED:
3188 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003189 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003190 break;
3191
3192 case DISCOV_TYPE_BREDR:
3193 break;
3194
3195 default:
3196 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3197 }
3198}
3199
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003200static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003201 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003202{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003203 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003204 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003205 struct hci_cp_le_set_scan_param param_cp;
3206 struct hci_cp_le_set_scan_enable enable_cp;
3207 struct hci_cp_inquiry inq_cp;
3208 struct hci_request req;
3209 /* General inquiry access code (GIAC) */
3210 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003211 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003212 int err;
3213
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003214 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003215
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003216 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003217
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003218 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003219 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003220 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003221 goto failed;
3222 }
3223
Andre Guedes642be6c2012-03-21 00:03:37 -03003224 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3225 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3226 MGMT_STATUS_BUSY);
3227 goto failed;
3228 }
3229
Johan Hedbergff9ef572012-01-04 14:23:45 +02003230 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003231 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003232 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003233 goto failed;
3234 }
3235
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003236 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003237 if (!cmd) {
3238 err = -ENOMEM;
3239 goto failed;
3240 }
3241
Andre Guedes4aab14e2012-02-17 20:39:36 -03003242 hdev->discovery.type = cp->type;
3243
Andre Guedes7c307722013-04-30 15:29:28 -03003244 hci_req_init(&req, hdev);
3245
Andre Guedes4aab14e2012-02-17 20:39:36 -03003246 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003247 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003248 status = mgmt_bredr_support(hdev);
3249 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003250 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003251 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003252 mgmt_pending_remove(cmd);
3253 goto failed;
3254 }
3255
Andre Guedes7c307722013-04-30 15:29:28 -03003256 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3257 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3258 MGMT_STATUS_BUSY);
3259 mgmt_pending_remove(cmd);
3260 goto failed;
3261 }
3262
3263 hci_inquiry_cache_flush(hdev);
3264
3265 memset(&inq_cp, 0, sizeof(inq_cp));
3266 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003267 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003268 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003269 break;
3270
3271 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003272 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003273 status = mgmt_le_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 (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003282 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003283 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3284 MGMT_STATUS_NOT_SUPPORTED);
3285 mgmt_pending_remove(cmd);
3286 goto failed;
3287 }
3288
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003289 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003290 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3291 MGMT_STATUS_REJECTED);
3292 mgmt_pending_remove(cmd);
3293 goto failed;
3294 }
3295
3296 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3297 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3298 MGMT_STATUS_BUSY);
3299 mgmt_pending_remove(cmd);
3300 goto failed;
3301 }
3302
3303 memset(&param_cp, 0, sizeof(param_cp));
3304 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003305 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3306 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmann79830f62013-10-18 16:38:09 -07003307 param_cp.own_address_type = hdev->own_addr_type;
Andre Guedes7c307722013-04-30 15:29:28 -03003308 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3309 &param_cp);
3310
3311 memset(&enable_cp, 0, sizeof(enable_cp));
3312 enable_cp.enable = LE_SCAN_ENABLE;
3313 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3314 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3315 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003316 break;
3317
Andre Guedesf39799f2012-02-17 20:39:35 -03003318 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003319 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3320 MGMT_STATUS_INVALID_PARAMS);
3321 mgmt_pending_remove(cmd);
3322 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003323 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003324
Andre Guedes7c307722013-04-30 15:29:28 -03003325 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003326 if (err < 0)
3327 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003328 else
3329 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003330
3331failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003332 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003333 return err;
3334}
3335
Andre Guedes1183fdc2013-04-30 15:29:35 -03003336static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3337{
3338 struct pending_cmd *cmd;
3339 int err;
3340
3341 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3342 if (!cmd)
3343 return -ENOENT;
3344
3345 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3346 &hdev->discovery.type, sizeof(hdev->discovery.type));
3347 mgmt_pending_remove(cmd);
3348
3349 return err;
3350}
3351
Andre Guedes0e05bba2013-04-30 15:29:33 -03003352static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3353{
3354 BT_DBG("status %d", status);
3355
3356 hci_dev_lock(hdev);
3357
3358 if (status) {
3359 mgmt_stop_discovery_failed(hdev, status);
3360 goto unlock;
3361 }
3362
3363 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3364
3365unlock:
3366 hci_dev_unlock(hdev);
3367}
3368
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003369static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003370 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003371{
Johan Hedbergd9306502012-02-20 23:25:18 +02003372 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003373 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003374 struct hci_cp_remote_name_req_cancel cp;
3375 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003376 struct hci_request req;
3377 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003378 int err;
3379
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003380 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003381
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003382 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003383
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003384 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003385 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003386 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3387 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003388 goto unlock;
3389 }
3390
3391 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003392 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003393 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3394 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003395 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003396 }
3397
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003398 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003399 if (!cmd) {
3400 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003401 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003402 }
3403
Andre Guedes0e05bba2013-04-30 15:29:33 -03003404 hci_req_init(&req, hdev);
3405
Andre Guedese0d9727e2012-03-20 15:15:36 -03003406 switch (hdev->discovery.state) {
3407 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003408 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3409 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3410 } else {
3411 cancel_delayed_work(&hdev->le_scan_disable);
3412
3413 memset(&enable_cp, 0, sizeof(enable_cp));
3414 enable_cp.enable = LE_SCAN_DISABLE;
3415 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3416 sizeof(enable_cp), &enable_cp);
3417 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003418
Andre Guedese0d9727e2012-03-20 15:15:36 -03003419 break;
3420
3421 case DISCOVERY_RESOLVING:
3422 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003423 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003424 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003425 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003426 err = cmd_complete(sk, hdev->id,
3427 MGMT_OP_STOP_DISCOVERY, 0,
3428 &mgmt_cp->type,
3429 sizeof(mgmt_cp->type));
3430 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3431 goto unlock;
3432 }
3433
3434 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003435 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3436 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003437
3438 break;
3439
3440 default:
3441 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003442
3443 mgmt_pending_remove(cmd);
3444 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3445 MGMT_STATUS_FAILED, &mgmt_cp->type,
3446 sizeof(mgmt_cp->type));
3447 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003448 }
3449
Andre Guedes0e05bba2013-04-30 15:29:33 -03003450 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003451 if (err < 0)
3452 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003453 else
3454 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003455
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003456unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003457 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003458 return err;
3459}
3460
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003461static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003462 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003463{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003464 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003465 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003466 int err;
3467
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003468 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003469
Johan Hedberg561aafb2012-01-04 13:31:59 +02003470 hci_dev_lock(hdev);
3471
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003472 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003473 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003474 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003475 goto failed;
3476 }
3477
Johan Hedberga198e7b2012-02-17 14:27:06 +02003478 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003479 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003480 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003481 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003482 goto failed;
3483 }
3484
3485 if (cp->name_known) {
3486 e->name_state = NAME_KNOWN;
3487 list_del(&e->list);
3488 } else {
3489 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003490 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003491 }
3492
Johan Hedberge3846622013-01-09 15:29:33 +02003493 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3494 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003495
3496failed:
3497 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003498 return err;
3499}
3500
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003501static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003502 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003503{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003504 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003505 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003506 int err;
3507
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003508 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003509
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003510 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003511 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3512 MGMT_STATUS_INVALID_PARAMS,
3513 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003514
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003515 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003516
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003517 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003518 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003519 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003520 else
Szymon Janca6785be2012-12-13 15:11:21 +01003521 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003522
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003523 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003524 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003525
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003526 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003527
3528 return err;
3529}
3530
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003531static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003532 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003533{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003534 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003535 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003536 int err;
3537
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003538 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003539
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003540 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003541 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3542 MGMT_STATUS_INVALID_PARAMS,
3543 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003544
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003545 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003546
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003547 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003548 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003549 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003550 else
Szymon Janca6785be2012-12-13 15:11:21 +01003551 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003552
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003553 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003554 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003555
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003556 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003557
3558 return err;
3559}
3560
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003561static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3562 u16 len)
3563{
3564 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003565 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003566 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003567 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003568
3569 BT_DBG("%s", hdev->name);
3570
Szymon Jancc72d4b82012-03-16 16:02:57 +01003571 source = __le16_to_cpu(cp->source);
3572
3573 if (source > 0x0002)
3574 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3575 MGMT_STATUS_INVALID_PARAMS);
3576
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003577 hci_dev_lock(hdev);
3578
Szymon Jancc72d4b82012-03-16 16:02:57 +01003579 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003580 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3581 hdev->devid_product = __le16_to_cpu(cp->product);
3582 hdev->devid_version = __le16_to_cpu(cp->version);
3583
3584 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3585
Johan Hedberg890ea892013-03-15 17:06:52 -05003586 hci_req_init(&req, hdev);
3587 update_eir(&req);
3588 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003589
3590 hci_dev_unlock(hdev);
3591
3592 return err;
3593}
3594
Johan Hedberg4375f102013-09-25 13:26:10 +03003595static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3596{
3597 struct cmd_lookup match = { NULL, hdev };
3598
3599 if (status) {
3600 u8 mgmt_err = mgmt_status(status);
3601
3602 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3603 cmd_status_rsp, &mgmt_err);
3604 return;
3605 }
3606
3607 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3608 &match);
3609
3610 new_settings(hdev, match.sk);
3611
3612 if (match.sk)
3613 sock_put(match.sk);
3614}
3615
Marcel Holtmann21b51872013-10-10 09:47:53 -07003616static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3617 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003618{
3619 struct mgmt_mode *cp = data;
3620 struct pending_cmd *cmd;
3621 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003622 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003623 int err;
3624
3625 BT_DBG("request for %s", hdev->name);
3626
Johan Hedberge6fe7982013-10-02 15:45:22 +03003627 status = mgmt_le_support(hdev);
3628 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003629 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003630 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003631
3632 if (cp->val != 0x00 && cp->val != 0x01)
3633 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3634 MGMT_STATUS_INVALID_PARAMS);
3635
3636 hci_dev_lock(hdev);
3637
3638 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003639 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003640
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003641 /* The following conditions are ones which mean that we should
3642 * not do any HCI communication but directly send a mgmt
3643 * response to user space (after toggling the flag if
3644 * necessary).
3645 */
3646 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003647 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003648 bool changed = false;
3649
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003650 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3651 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003652 changed = true;
3653 }
3654
3655 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3656 if (err < 0)
3657 goto unlock;
3658
3659 if (changed)
3660 err = new_settings(hdev, sk);
3661
3662 goto unlock;
3663 }
3664
3665 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3666 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3667 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3668 MGMT_STATUS_BUSY);
3669 goto unlock;
3670 }
3671
3672 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3673 if (!cmd) {
3674 err = -ENOMEM;
3675 goto unlock;
3676 }
3677
3678 hci_req_init(&req, hdev);
3679
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003680 if (val)
3681 enable_advertising(&req);
3682 else
3683 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003684
3685 err = hci_req_run(&req, set_advertising_complete);
3686 if (err < 0)
3687 mgmt_pending_remove(cmd);
3688
3689unlock:
3690 hci_dev_unlock(hdev);
3691 return err;
3692}
3693
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003694static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3695 void *data, u16 len)
3696{
3697 struct mgmt_cp_set_static_address *cp = data;
3698 int err;
3699
3700 BT_DBG("%s", hdev->name);
3701
Marcel Holtmann62af4442013-10-02 22:10:32 -07003702 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003703 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003704 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003705
3706 if (hdev_is_powered(hdev))
3707 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3708 MGMT_STATUS_REJECTED);
3709
3710 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3711 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3712 return cmd_status(sk, hdev->id,
3713 MGMT_OP_SET_STATIC_ADDRESS,
3714 MGMT_STATUS_INVALID_PARAMS);
3715
3716 /* Two most significant bits shall be set */
3717 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3718 return cmd_status(sk, hdev->id,
3719 MGMT_OP_SET_STATIC_ADDRESS,
3720 MGMT_STATUS_INVALID_PARAMS);
3721 }
3722
3723 hci_dev_lock(hdev);
3724
3725 bacpy(&hdev->static_addr, &cp->bdaddr);
3726
3727 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3728
3729 hci_dev_unlock(hdev);
3730
3731 return err;
3732}
3733
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003734static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3735 void *data, u16 len)
3736{
3737 struct mgmt_cp_set_scan_params *cp = data;
3738 __u16 interval, window;
3739 int err;
3740
3741 BT_DBG("%s", hdev->name);
3742
3743 if (!lmp_le_capable(hdev))
3744 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3745 MGMT_STATUS_NOT_SUPPORTED);
3746
3747 interval = __le16_to_cpu(cp->interval);
3748
3749 if (interval < 0x0004 || interval > 0x4000)
3750 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3751 MGMT_STATUS_INVALID_PARAMS);
3752
3753 window = __le16_to_cpu(cp->window);
3754
3755 if (window < 0x0004 || window > 0x4000)
3756 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3757 MGMT_STATUS_INVALID_PARAMS);
3758
Marcel Holtmann899e1072013-10-14 09:55:32 -07003759 if (window > interval)
3760 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3761 MGMT_STATUS_INVALID_PARAMS);
3762
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003763 hci_dev_lock(hdev);
3764
3765 hdev->le_scan_interval = interval;
3766 hdev->le_scan_window = window;
3767
3768 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3769
3770 hci_dev_unlock(hdev);
3771
3772 return err;
3773}
3774
Johan Hedberg33e38b32013-03-15 17:07:05 -05003775static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3776{
3777 struct pending_cmd *cmd;
3778
3779 BT_DBG("status 0x%02x", status);
3780
3781 hci_dev_lock(hdev);
3782
3783 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3784 if (!cmd)
3785 goto unlock;
3786
3787 if (status) {
3788 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3789 mgmt_status(status));
3790 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003791 struct mgmt_mode *cp = cmd->param;
3792
3793 if (cp->val)
3794 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3795 else
3796 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3797
Johan Hedberg33e38b32013-03-15 17:07:05 -05003798 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3799 new_settings(hdev, cmd->sk);
3800 }
3801
3802 mgmt_pending_remove(cmd);
3803
3804unlock:
3805 hci_dev_unlock(hdev);
3806}
3807
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003808static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003809 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003810{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003811 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003812 struct pending_cmd *cmd;
3813 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003814 int err;
3815
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003816 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003817
Johan Hedberg56f87902013-10-02 13:43:13 +03003818 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3819 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003820 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3821 MGMT_STATUS_NOT_SUPPORTED);
3822
Johan Hedberga7e80f22013-01-09 16:05:19 +02003823 if (cp->val != 0x00 && cp->val != 0x01)
3824 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3825 MGMT_STATUS_INVALID_PARAMS);
3826
Johan Hedberg5400c042012-02-21 16:40:33 +02003827 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003828 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003829 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003830
3831 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003832 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003833 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003834
3835 hci_dev_lock(hdev);
3836
Johan Hedberg05cbf292013-03-15 17:07:07 -05003837 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3838 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3839 MGMT_STATUS_BUSY);
3840 goto unlock;
3841 }
3842
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003843 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3844 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3845 hdev);
3846 goto unlock;
3847 }
3848
Johan Hedberg33e38b32013-03-15 17:07:05 -05003849 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3850 data, len);
3851 if (!cmd) {
3852 err = -ENOMEM;
3853 goto unlock;
3854 }
3855
3856 hci_req_init(&req, hdev);
3857
Johan Hedberg406d7802013-03-15 17:07:09 -05003858 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003859
3860 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003861 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003862 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003863 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003864 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003865 }
3866
Johan Hedberg33e38b32013-03-15 17:07:05 -05003867unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003868 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003869
Antti Julkuf6422ec2011-06-22 13:11:56 +03003870 return err;
3871}
3872
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003873static void set_bredr_scan(struct hci_request *req)
3874{
3875 struct hci_dev *hdev = req->hdev;
3876 u8 scan = 0;
3877
3878 /* Ensure that fast connectable is disabled. This function will
3879 * not do anything if the page scan parameters are already what
3880 * they should be.
3881 */
3882 write_fast_connectable(req, false);
3883
3884 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3885 scan |= SCAN_PAGE;
3886 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3887 scan |= SCAN_INQUIRY;
3888
3889 if (scan)
3890 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3891}
3892
Johan Hedberg0663ca22013-10-02 13:43:14 +03003893static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3894{
3895 struct pending_cmd *cmd;
3896
3897 BT_DBG("status 0x%02x", status);
3898
3899 hci_dev_lock(hdev);
3900
3901 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3902 if (!cmd)
3903 goto unlock;
3904
3905 if (status) {
3906 u8 mgmt_err = mgmt_status(status);
3907
3908 /* We need to restore the flag if related HCI commands
3909 * failed.
3910 */
3911 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3912
3913 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3914 } else {
3915 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3916 new_settings(hdev, cmd->sk);
3917 }
3918
3919 mgmt_pending_remove(cmd);
3920
3921unlock:
3922 hci_dev_unlock(hdev);
3923}
3924
3925static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3926{
3927 struct mgmt_mode *cp = data;
3928 struct pending_cmd *cmd;
3929 struct hci_request req;
3930 int err;
3931
3932 BT_DBG("request for %s", hdev->name);
3933
3934 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3935 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3936 MGMT_STATUS_NOT_SUPPORTED);
3937
3938 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3939 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3940 MGMT_STATUS_REJECTED);
3941
3942 if (cp->val != 0x00 && cp->val != 0x01)
3943 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3944 MGMT_STATUS_INVALID_PARAMS);
3945
3946 hci_dev_lock(hdev);
3947
3948 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3949 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3950 goto unlock;
3951 }
3952
3953 if (!hdev_is_powered(hdev)) {
3954 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003955 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3956 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3957 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3958 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3959 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3960 }
3961
3962 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3963
3964 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3965 if (err < 0)
3966 goto unlock;
3967
3968 err = new_settings(hdev, sk);
3969 goto unlock;
3970 }
3971
3972 /* Reject disabling when powered on */
3973 if (!cp->val) {
3974 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3975 MGMT_STATUS_REJECTED);
3976 goto unlock;
3977 }
3978
3979 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3980 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3981 MGMT_STATUS_BUSY);
3982 goto unlock;
3983 }
3984
3985 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3986 if (!cmd) {
3987 err = -ENOMEM;
3988 goto unlock;
3989 }
3990
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07003991 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03003992 * generates the correct flags.
3993 */
3994 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3995
3996 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003997
3998 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3999 set_bredr_scan(&req);
4000
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004001 /* Since only the advertising data flags will change, there
4002 * is no need to update the scan response data.
4003 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004004 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004005
Johan Hedberg0663ca22013-10-02 13:43:14 +03004006 err = hci_req_run(&req, set_bredr_complete);
4007 if (err < 0)
4008 mgmt_pending_remove(cmd);
4009
4010unlock:
4011 hci_dev_unlock(hdev);
4012 return err;
4013}
4014
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004015static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4016 void *data, u16 len)
4017{
4018 struct mgmt_mode *cp = data;
4019 struct pending_cmd *cmd;
4020 u8 status;
4021 int err;
4022
4023 BT_DBG("request for %s", hdev->name);
4024
4025 status = mgmt_bredr_support(hdev);
4026 if (status)
4027 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4028 status);
4029
Marcel Holtmann5afeac142014-01-10 02:07:27 -08004030 if (!lmp_sc_capable(hdev) &&
4031 !test_bit(HCI_FORCE_SC, &hdev->dev_flags))
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004032 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4033 MGMT_STATUS_NOT_SUPPORTED);
4034
4035 if (cp->val != 0x00 && cp->val != 0x01)
4036 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4037 MGMT_STATUS_INVALID_PARAMS);
4038
4039 hci_dev_lock(hdev);
4040
4041 if (!hdev_is_powered(hdev)) {
4042 bool changed;
4043
4044 if (cp->val)
4045 changed = !test_and_set_bit(HCI_SC_ENABLED,
4046 &hdev->dev_flags);
4047 else
4048 changed = test_and_clear_bit(HCI_SC_ENABLED,
4049 &hdev->dev_flags);
4050
4051 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4052 if (err < 0)
4053 goto failed;
4054
4055 if (changed)
4056 err = new_settings(hdev, sk);
4057
4058 goto failed;
4059 }
4060
4061 if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
4062 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4063 MGMT_STATUS_BUSY);
4064 goto failed;
4065 }
4066
4067 if (!!cp->val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
4068 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4069 goto failed;
4070 }
4071
4072 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4073 if (!cmd) {
4074 err = -ENOMEM;
4075 goto failed;
4076 }
4077
4078 err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &cp->val);
4079 if (err < 0) {
4080 mgmt_pending_remove(cmd);
4081 goto failed;
4082 }
4083
4084failed:
4085 hci_dev_unlock(hdev);
4086 return err;
4087}
4088
Johan Hedberg3f706b72013-01-20 14:27:16 +02004089static bool ltk_is_valid(struct mgmt_ltk_info *key)
4090{
Johan Hedberg44b20d32013-01-20 14:27:17 +02004091 if (key->authenticated != 0x00 && key->authenticated != 0x01)
4092 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004093 if (key->master != 0x00 && key->master != 0x01)
4094 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004095 if (!bdaddr_type_is_le(key->addr.type))
4096 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004097 return true;
4098}
4099
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004100static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004101 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004102{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004103 struct mgmt_cp_load_long_term_keys *cp = cp_data;
4104 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004105 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004106
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004107 BT_DBG("request for %s", hdev->name);
4108
4109 if (!lmp_le_capable(hdev))
4110 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4111 MGMT_STATUS_NOT_SUPPORTED);
4112
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004113 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004114
4115 expected_len = sizeof(*cp) + key_count *
4116 sizeof(struct mgmt_ltk_info);
4117 if (expected_len != len) {
4118 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004119 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004120 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02004121 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004122 }
4123
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004124 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004125
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004126 for (i = 0; i < key_count; i++) {
4127 struct mgmt_ltk_info *key = &cp->keys[i];
4128
Johan Hedberg3f706b72013-01-20 14:27:16 +02004129 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004130 return cmd_status(sk, hdev->id,
4131 MGMT_OP_LOAD_LONG_TERM_KEYS,
4132 MGMT_STATUS_INVALID_PARAMS);
4133 }
4134
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004135 hci_dev_lock(hdev);
4136
4137 hci_smp_ltks_clear(hdev);
4138
4139 for (i = 0; i < key_count; i++) {
4140 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004141 u8 type, addr_type;
4142
4143 if (key->addr.type == BDADDR_LE_PUBLIC)
4144 addr_type = ADDR_LE_DEV_PUBLIC;
4145 else
4146 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004147
4148 if (key->master)
4149 type = HCI_SMP_LTK;
4150 else
4151 type = HCI_SMP_LTK_SLAVE;
4152
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004153 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004154 type, 0, key->authenticated, key->val,
4155 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004156 }
4157
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004158 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4159 NULL, 0);
4160
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004161 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004162
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004163 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004164}
4165
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004166static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004167 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4168 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004169 bool var_len;
4170 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004171} mgmt_handlers[] = {
4172 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004173 { read_version, false, MGMT_READ_VERSION_SIZE },
4174 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4175 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4176 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4177 { set_powered, false, MGMT_SETTING_SIZE },
4178 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4179 { set_connectable, false, MGMT_SETTING_SIZE },
4180 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4181 { set_pairable, false, MGMT_SETTING_SIZE },
4182 { set_link_security, false, MGMT_SETTING_SIZE },
4183 { set_ssp, false, MGMT_SETTING_SIZE },
4184 { set_hs, false, MGMT_SETTING_SIZE },
4185 { set_le, false, MGMT_SETTING_SIZE },
4186 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4187 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4188 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4189 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4190 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4191 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4192 { disconnect, false, MGMT_DISCONNECT_SIZE },
4193 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4194 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4195 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4196 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4197 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4198 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4199 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4200 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4201 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4202 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4203 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4204 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
4205 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
4206 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4207 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4208 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4209 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4210 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4211 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004212 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004213 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004214 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004215 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004216 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004217 { set_secure_conn, false, MGMT_SETTING_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004218};
4219
4220
Johan Hedberg03811012010-12-08 00:21:06 +02004221int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4222{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004223 void *buf;
4224 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004225 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004226 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004227 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004228 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004229 int err;
4230
4231 BT_DBG("got %zu bytes", msglen);
4232
4233 if (msglen < sizeof(*hdr))
4234 return -EINVAL;
4235
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004236 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004237 if (!buf)
4238 return -ENOMEM;
4239
4240 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4241 err = -EFAULT;
4242 goto done;
4243 }
4244
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004245 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004246 opcode = __le16_to_cpu(hdr->opcode);
4247 index = __le16_to_cpu(hdr->index);
4248 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004249
4250 if (len != msglen - sizeof(*hdr)) {
4251 err = -EINVAL;
4252 goto done;
4253 }
4254
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004255 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004256 hdev = hci_dev_get(index);
4257 if (!hdev) {
4258 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004259 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004260 goto done;
4261 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004262
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004263 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4264 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004265 err = cmd_status(sk, index, opcode,
4266 MGMT_STATUS_INVALID_INDEX);
4267 goto done;
4268 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004269 }
4270
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004271 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004272 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004273 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004274 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004275 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004276 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004277 }
4278
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004279 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004280 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004281 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004282 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004283 goto done;
4284 }
4285
Johan Hedbergbe22b542012-03-01 22:24:41 +02004286 handler = &mgmt_handlers[opcode];
4287
4288 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004289 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004290 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004291 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004292 goto done;
4293 }
4294
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004295 if (hdev)
4296 mgmt_init_hdev(sk, hdev);
4297
4298 cp = buf + sizeof(*hdr);
4299
Johan Hedbergbe22b542012-03-01 22:24:41 +02004300 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004301 if (err < 0)
4302 goto done;
4303
Johan Hedberg03811012010-12-08 00:21:06 +02004304 err = msglen;
4305
4306done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004307 if (hdev)
4308 hci_dev_put(hdev);
4309
Johan Hedberg03811012010-12-08 00:21:06 +02004310 kfree(buf);
4311 return err;
4312}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004313
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004314void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004315{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004316 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004317 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004318
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004319 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004320}
4321
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004322void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004323{
Johan Hedberg5f159032012-03-02 03:13:19 +02004324 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004325
Marcel Holtmann1514b892013-10-06 08:25:01 -07004326 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004327 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004328
Johan Hedberg744cf192011-11-08 20:40:14 +02004329 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004330
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004331 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004332}
4333
Johan Hedberg229ab392013-03-15 17:06:53 -05004334static void powered_complete(struct hci_dev *hdev, u8 status)
4335{
4336 struct cmd_lookup match = { NULL, hdev };
4337
4338 BT_DBG("status 0x%02x", status);
4339
4340 hci_dev_lock(hdev);
4341
4342 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4343
4344 new_settings(hdev, match.sk);
4345
4346 hci_dev_unlock(hdev);
4347
4348 if (match.sk)
4349 sock_put(match.sk);
4350}
4351
Johan Hedberg70da6242013-03-15 17:06:51 -05004352static int powered_update_hci(struct hci_dev *hdev)
4353{
Johan Hedberg890ea892013-03-15 17:06:52 -05004354 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004355 u8 link_sec;
4356
Johan Hedberg890ea892013-03-15 17:06:52 -05004357 hci_req_init(&req, hdev);
4358
Johan Hedberg70da6242013-03-15 17:06:51 -05004359 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4360 !lmp_host_ssp_capable(hdev)) {
4361 u8 ssp = 1;
4362
Johan Hedberg890ea892013-03-15 17:06:52 -05004363 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004364 }
4365
Johan Hedbergc73eee92013-04-19 18:35:21 +03004366 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4367 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004368 struct hci_cp_write_le_host_supported cp;
4369
4370 cp.le = 1;
4371 cp.simul = lmp_le_br_capable(hdev);
4372
4373 /* Check first if we already have the right
4374 * host state (host features set)
4375 */
4376 if (cp.le != lmp_host_le_capable(hdev) ||
4377 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004378 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4379 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004380 }
4381
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004382 if (lmp_le_capable(hdev)) {
4383 /* Set random address to static address if configured */
4384 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4385 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4386 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004387
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004388 /* Make sure the controller has a good default for
4389 * advertising data. This also applies to the case
4390 * where BR/EDR was toggled during the AUTO_OFF phase.
4391 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004392 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004393 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004394 update_scan_rsp_data(&req);
4395 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004396
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004397 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4398 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004399 }
4400
Johan Hedberg70da6242013-03-15 17:06:51 -05004401 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4402 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004403 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4404 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004405
4406 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004407 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4408 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004409 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004410 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004411 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004412 }
4413
Johan Hedberg229ab392013-03-15 17:06:53 -05004414 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004415}
4416
Johan Hedberg744cf192011-11-08 20:40:14 +02004417int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004418{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004419 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004420 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4421 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004422 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004423
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004424 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4425 return 0;
4426
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004427 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004428 if (powered_update_hci(hdev) == 0)
4429 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004430
Johan Hedberg229ab392013-03-15 17:06:53 -05004431 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4432 &match);
4433 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004434 }
4435
Johan Hedberg229ab392013-03-15 17:06:53 -05004436 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4437 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4438
4439 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4440 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4441 zero_cod, sizeof(zero_cod), NULL);
4442
4443new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004444 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004445
4446 if (match.sk)
4447 sock_put(match.sk);
4448
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004449 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004450}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004451
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004452void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004453{
4454 struct pending_cmd *cmd;
4455 u8 status;
4456
4457 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4458 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004459 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004460
4461 if (err == -ERFKILL)
4462 status = MGMT_STATUS_RFKILLED;
4463 else
4464 status = MGMT_STATUS_FAILED;
4465
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004466 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004467
4468 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004469}
4470
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004471void mgmt_discoverable_timeout(struct hci_dev *hdev)
4472{
4473 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004474
4475 hci_dev_lock(hdev);
4476
4477 /* When discoverable timeout triggers, then just make sure
4478 * the limited discoverable flag is cleared. Even in the case
4479 * of a timeout triggered from general discoverable, it is
4480 * safe to unconditionally clear the flag.
4481 */
4482 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004483 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004484
4485 hci_req_init(&req, hdev);
Johan Hedberg4b580612013-10-19 23:38:21 +03004486 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4487 u8 scan = SCAN_PAGE;
4488 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
4489 sizeof(scan), &scan);
4490 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004491 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004492 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004493 hci_req_run(&req, NULL);
4494
4495 hdev->discov_timeout = 0;
4496
Johan Hedberg9a43e252013-10-20 19:00:07 +03004497 new_settings(hdev, NULL);
4498
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004499 hci_dev_unlock(hdev);
4500}
4501
Marcel Holtmann86a75642013-10-15 06:33:54 -07004502void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004503{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004504 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004505
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004506 /* Nothing needed here if there's a pending command since that
4507 * commands request completion callback takes care of everything
4508 * necessary.
4509 */
4510 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004511 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004512
Johan Hedberg9a43e252013-10-20 19:00:07 +03004513 if (discoverable) {
Marcel Holtmann86a75642013-10-15 06:33:54 -07004514 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004515 } else {
4516 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmann86a75642013-10-15 06:33:54 -07004517 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004518 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004519
Johan Hedberg9a43e252013-10-20 19:00:07 +03004520 if (changed) {
4521 struct hci_request req;
4522
4523 /* In case this change in discoverable was triggered by
4524 * a disabling of connectable there could be a need to
4525 * update the advertising flags.
4526 */
4527 hci_req_init(&req, hdev);
4528 update_adv_data(&req);
4529 hci_req_run(&req, NULL);
4530
Marcel Holtmann86a75642013-10-15 06:33:54 -07004531 new_settings(hdev, NULL);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004532 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004533}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004534
Marcel Holtmanna3309162013-10-15 06:33:55 -07004535void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004536{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004537 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004538
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004539 /* Nothing needed here if there's a pending command since that
4540 * commands request completion callback takes care of everything
4541 * necessary.
4542 */
4543 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004544 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004545
Marcel Holtmanna3309162013-10-15 06:33:55 -07004546 if (connectable)
4547 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4548 else
4549 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004550
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004551 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004552 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004553}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004554
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004555void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004556{
Johan Hedbergca69b792011-11-11 18:10:00 +02004557 u8 mgmt_err = mgmt_status(status);
4558
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004559 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004560 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004561 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004562
4563 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004564 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004565 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004566}
4567
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004568void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4569 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004570{
Johan Hedberg86742e12011-11-07 23:13:38 +02004571 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004572
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004573 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004574
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004575 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004576 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004577 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004578 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004579 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004580 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004581
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004582 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004583}
Johan Hedbergf7520542011-01-20 12:34:39 +02004584
Marcel Holtmann083368f2013-10-15 14:26:29 -07004585void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004586{
4587 struct mgmt_ev_new_long_term_key ev;
4588
4589 memset(&ev, 0, sizeof(ev));
4590
4591 ev.store_hint = persistent;
4592 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004593 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004594 ev.key.authenticated = key->authenticated;
4595 ev.key.enc_size = key->enc_size;
4596 ev.key.ediv = key->ediv;
4597
4598 if (key->type == HCI_SMP_LTK)
4599 ev.key.master = 1;
4600
4601 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4602 memcpy(ev.key.val, key->val, sizeof(key->val));
4603
Marcel Holtmann083368f2013-10-15 14:26:29 -07004604 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004605}
4606
Marcel Holtmann94933992013-10-15 10:26:39 -07004607static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4608 u8 data_len)
4609{
4610 eir[eir_len++] = sizeof(type) + data_len;
4611 eir[eir_len++] = type;
4612 memcpy(&eir[eir_len], data, data_len);
4613 eir_len += data_len;
4614
4615 return eir_len;
4616}
4617
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004618void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4619 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4620 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004621{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004622 char buf[512];
4623 struct mgmt_ev_device_connected *ev = (void *) buf;
4624 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004625
Johan Hedbergb644ba32012-01-17 21:48:47 +02004626 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004627 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004628
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004629 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004630
Johan Hedbergb644ba32012-01-17 21:48:47 +02004631 if (name_len > 0)
4632 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004633 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004634
4635 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004636 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004637 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004638
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004639 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004640
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004641 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4642 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004643}
4644
Johan Hedberg8962ee72011-01-20 12:40:27 +02004645static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4646{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004647 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004648 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004649 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004650
Johan Hedberg88c3df12012-02-09 14:27:38 +02004651 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4652 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004653
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004654 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004655 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004656
4657 *sk = cmd->sk;
4658 sock_hold(*sk);
4659
Johan Hedberga664b5b2011-02-19 12:06:02 -03004660 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004661}
4662
Johan Hedberg124f6e32012-02-09 13:50:12 +02004663static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004664{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004665 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004666 struct mgmt_cp_unpair_device *cp = cmd->param;
4667 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004668
4669 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004670 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4671 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004672
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004673 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4674
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004675 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004676
4677 mgmt_pending_remove(cmd);
4678}
4679
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004680void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4681 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004682{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004683 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004684 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004685
Andre Guedes57eb7762013-10-30 19:01:41 -03004686 if (link_type != ACL_LINK && link_type != LE_LINK)
4687 return;
4688
Johan Hedberg744cf192011-11-08 20:40:14 +02004689 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004690
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004691 bacpy(&ev.addr.bdaddr, bdaddr);
4692 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4693 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004694
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004695 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004696
4697 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004698 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004699
Johan Hedberg124f6e32012-02-09 13:50:12 +02004700 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004701 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004702}
4703
Marcel Holtmann78929242013-10-06 23:55:47 -07004704void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4705 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004706{
Andre Guedes3655bba2013-10-30 19:01:40 -03004707 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
4708 struct mgmt_cp_disconnect *cp;
Johan Hedberg88c3df12012-02-09 14:27:38 +02004709 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004710 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004711
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004712 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4713 hdev);
4714
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004715 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004716 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004717 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004718
Andre Guedes3655bba2013-10-30 19:01:40 -03004719 cp = cmd->param;
4720
4721 if (bacmp(bdaddr, &cp->addr.bdaddr))
4722 return;
4723
4724 if (cp->addr.type != bdaddr_type)
4725 return;
4726
Johan Hedberg88c3df12012-02-09 14:27:38 +02004727 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes3655bba2013-10-30 19:01:40 -03004728 rp.addr.type = bdaddr_type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004729
Marcel Holtmann78929242013-10-06 23:55:47 -07004730 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4731 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004732
Johan Hedberga664b5b2011-02-19 12:06:02 -03004733 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004734}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004735
Marcel Holtmann445608d2013-10-06 23:55:48 -07004736void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4737 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004738{
4739 struct mgmt_ev_connect_failed ev;
4740
Johan Hedberg4c659c32011-11-07 23:13:39 +02004741 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004742 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004743 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004744
Marcel Holtmann445608d2013-10-06 23:55:48 -07004745 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004746}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004747
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004748void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004749{
4750 struct mgmt_ev_pin_code_request ev;
4751
Johan Hedbergd8457692012-02-17 14:24:57 +02004752 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004753 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004754 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004755
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004756 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004757}
4758
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004759void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4760 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004761{
4762 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004763 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004764
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004765 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004766 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004767 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004768
Johan Hedbergd8457692012-02-17 14:24:57 +02004769 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004770 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004771
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004772 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
4773 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004774
Johan Hedberga664b5b2011-02-19 12:06:02 -03004775 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004776}
4777
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004778void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4779 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004780{
4781 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004782 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004783
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004784 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004785 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004786 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004787
Johan Hedbergd8457692012-02-17 14:24:57 +02004788 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004789 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004790
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004791 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
4792 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004793
Johan Hedberga664b5b2011-02-19 12:06:02 -03004794 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004795}
Johan Hedberga5c29682011-02-19 12:05:57 -03004796
Johan Hedberg744cf192011-11-08 20:40:14 +02004797int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004798 u8 link_type, u8 addr_type, __le32 value,
4799 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004800{
4801 struct mgmt_ev_user_confirm_request ev;
4802
Johan Hedberg744cf192011-11-08 20:40:14 +02004803 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004804
Johan Hedberg272d90d2012-02-09 15:26:12 +02004805 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004806 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004807 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02004808 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004809
Johan Hedberg744cf192011-11-08 20:40:14 +02004810 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004811 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004812}
4813
Johan Hedberg272d90d2012-02-09 15:26:12 +02004814int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004815 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004816{
4817 struct mgmt_ev_user_passkey_request ev;
4818
4819 BT_DBG("%s", hdev->name);
4820
Johan Hedberg272d90d2012-02-09 15:26:12 +02004821 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004822 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004823
4824 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004825 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004826}
4827
Brian Gix0df4c182011-11-16 13:53:13 -08004828static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004829 u8 link_type, u8 addr_type, u8 status,
4830 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004831{
4832 struct pending_cmd *cmd;
4833 struct mgmt_rp_user_confirm_reply rp;
4834 int err;
4835
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004836 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004837 if (!cmd)
4838 return -ENOENT;
4839
Johan Hedberg272d90d2012-02-09 15:26:12 +02004840 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004841 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004842 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004843 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004844
Johan Hedberga664b5b2011-02-19 12:06:02 -03004845 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004846
4847 return err;
4848}
4849
Johan Hedberg744cf192011-11-08 20:40:14 +02004850int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004851 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004852{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004853 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004854 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004855}
4856
Johan Hedberg272d90d2012-02-09 15:26:12 +02004857int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004858 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004859{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004860 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004861 status,
4862 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004863}
Johan Hedberg2a611692011-02-19 12:06:00 -03004864
Brian Gix604086b2011-11-23 08:28:33 -08004865int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004866 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004867{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004868 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004869 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004870}
4871
Johan Hedberg272d90d2012-02-09 15:26:12 +02004872int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004873 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004874{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004875 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004876 status,
4877 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004878}
4879
Johan Hedberg92a25252012-09-06 18:39:26 +03004880int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4881 u8 link_type, u8 addr_type, u32 passkey,
4882 u8 entered)
4883{
4884 struct mgmt_ev_passkey_notify ev;
4885
4886 BT_DBG("%s", hdev->name);
4887
4888 bacpy(&ev.addr.bdaddr, bdaddr);
4889 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4890 ev.passkey = __cpu_to_le32(passkey);
4891 ev.entered = entered;
4892
4893 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4894}
4895
Marcel Holtmanne5460992013-10-15 14:26:23 -07004896void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4897 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004898{
4899 struct mgmt_ev_auth_failed ev;
4900
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004901 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004902 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004903 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004904
Marcel Holtmanne5460992013-10-15 14:26:23 -07004905 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004906}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004907
Marcel Holtmann464996a2013-10-15 14:26:24 -07004908void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004909{
4910 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07004911 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004912
4913 if (status) {
4914 u8 mgmt_err = mgmt_status(status);
4915 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004916 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07004917 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004918 }
4919
Marcel Holtmann464996a2013-10-15 14:26:24 -07004920 if (test_bit(HCI_AUTH, &hdev->flags))
4921 changed = !test_and_set_bit(HCI_LINK_SECURITY,
4922 &hdev->dev_flags);
4923 else
4924 changed = test_and_clear_bit(HCI_LINK_SECURITY,
4925 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02004926
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004927 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004928 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004929
Johan Hedberg47990ea2012-02-22 11:58:37 +02004930 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07004931 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004932
4933 if (match.sk)
4934 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004935}
4936
Johan Hedberg890ea892013-03-15 17:06:52 -05004937static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004938{
Johan Hedberg890ea892013-03-15 17:06:52 -05004939 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004940 struct hci_cp_write_eir cp;
4941
Johan Hedberg976eb202012-10-24 21:12:01 +03004942 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004943 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004944
Johan Hedbergc80da272012-02-22 15:38:48 +02004945 memset(hdev->eir, 0, sizeof(hdev->eir));
4946
Johan Hedbergcacaf522012-02-21 00:52:42 +02004947 memset(&cp, 0, sizeof(cp));
4948
Johan Hedberg890ea892013-03-15 17:06:52 -05004949 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004950}
4951
Marcel Holtmann3e248562013-10-15 14:26:25 -07004952void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004953{
4954 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004955 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004956 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004957
4958 if (status) {
4959 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004960
4961 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004962 &hdev->dev_flags)) {
4963 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004964 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004965 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004966
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004967 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4968 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004969 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004970 }
4971
4972 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004973 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004974 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004975 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4976 if (!changed)
4977 changed = test_and_clear_bit(HCI_HS_ENABLED,
4978 &hdev->dev_flags);
4979 else
4980 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004981 }
4982
4983 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4984
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004985 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07004986 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004987
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004988 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004989 sock_put(match.sk);
4990
Johan Hedberg890ea892013-03-15 17:06:52 -05004991 hci_req_init(&req, hdev);
4992
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004993 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004994 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004995 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004996 clear_eir(&req);
4997
4998 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004999}
5000
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005001void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
5002{
5003 struct cmd_lookup match = { NULL, hdev };
5004 bool changed = false;
5005
5006 if (status) {
5007 u8 mgmt_err = mgmt_status(status);
5008
5009 if (enable && test_and_clear_bit(HCI_SC_ENABLED,
5010 &hdev->dev_flags))
5011 new_settings(hdev, NULL);
5012
5013 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5014 cmd_status_rsp, &mgmt_err);
5015 return;
5016 }
5017
5018 if (enable)
5019 changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
5020 else
5021 changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
5022
5023 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5024 settings_rsp, &match);
5025
5026 if (changed)
5027 new_settings(hdev, match.sk);
5028
5029 if (match.sk)
5030 sock_put(match.sk);
5031}
5032
Johan Hedberg92da6092013-03-15 17:06:55 -05005033static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02005034{
5035 struct cmd_lookup *match = data;
5036
Johan Hedberg90e70452012-02-23 23:09:40 +02005037 if (match->sk == NULL) {
5038 match->sk = cmd->sk;
5039 sock_hold(match->sk);
5040 }
Johan Hedberg90e70452012-02-23 23:09:40 +02005041}
5042
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005043void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
5044 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005045{
Johan Hedberg90e70452012-02-23 23:09:40 +02005046 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005047
Johan Hedberg92da6092013-03-15 17:06:55 -05005048 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
5049 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
5050 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02005051
5052 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005053 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
5054 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02005055
5056 if (match.sk)
5057 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005058}
5059
Marcel Holtmann7667da32013-10-15 14:26:27 -07005060void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02005061{
Johan Hedbergb312b1612011-03-16 14:29:37 +02005062 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05005063 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005064
Johan Hedberg13928972013-03-15 17:07:00 -05005065 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07005066 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005067
5068 memset(&ev, 0, sizeof(ev));
5069 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005070 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005071
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005072 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05005073 if (!cmd) {
5074 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02005075
Johan Hedberg13928972013-03-15 17:07:00 -05005076 /* If this is a HCI command related to powering on the
5077 * HCI dev don't send any mgmt signals.
5078 */
5079 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07005080 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005081 }
5082
Marcel Holtmann7667da32013-10-15 14:26:27 -07005083 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
5084 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005085}
Szymon Jancc35938b2011-03-22 13:12:21 +01005086
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005087void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
5088 u8 *randomizer192, u8 *hash256,
5089 u8 *randomizer256, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01005090{
5091 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01005092
Johan Hedberg744cf192011-11-08 20:40:14 +02005093 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01005094
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005095 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01005096 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005097 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01005098
5099 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005100 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
5101 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01005102 } else {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005103 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
5104 hash256 && randomizer256) {
5105 struct mgmt_rp_read_local_oob_ext_data rp;
Szymon Jancc35938b2011-03-22 13:12:21 +01005106
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005107 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
5108 memcpy(rp.randomizer192, randomizer192,
5109 sizeof(rp.randomizer192));
Szymon Jancc35938b2011-03-22 13:12:21 +01005110
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005111 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
5112 memcpy(rp.randomizer256, randomizer256,
5113 sizeof(rp.randomizer256));
5114
5115 cmd_complete(cmd->sk, hdev->id,
5116 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5117 &rp, sizeof(rp));
5118 } else {
5119 struct mgmt_rp_read_local_oob_data rp;
5120
5121 memcpy(rp.hash, hash192, sizeof(rp.hash));
5122 memcpy(rp.randomizer, randomizer192,
5123 sizeof(rp.randomizer));
5124
5125 cmd_complete(cmd->sk, hdev->id,
5126 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5127 &rp, sizeof(rp));
5128 }
Szymon Jancc35938b2011-03-22 13:12:21 +01005129 }
5130
5131 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01005132}
Johan Hedberge17acd42011-03-30 23:57:16 +03005133
Marcel Holtmann901801b2013-10-06 23:55:51 -07005134void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5135 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
5136 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03005137{
Johan Hedberge319d2e2012-01-15 19:51:59 +02005138 char buf[512];
5139 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02005140 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03005141
Andre Guedes12602d02013-04-30 15:29:40 -03005142 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005143 return;
Andre Guedes12602d02013-04-30 15:29:40 -03005144
Johan Hedberg1dc06092012-01-15 21:01:23 +02005145 /* Leave 5 bytes for a potential CoD field */
5146 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005147 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03005148
Johan Hedberg1dc06092012-01-15 21:01:23 +02005149 memset(buf, 0, sizeof(buf));
5150
Johan Hedberge319d2e2012-01-15 19:51:59 +02005151 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005152 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02005153 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02005154 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305155 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02005156 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305157 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03005158
Johan Hedberg1dc06092012-01-15 21:01:23 +02005159 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02005160 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03005161
Johan Hedberg1dc06092012-01-15 21:01:23 +02005162 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
5163 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005164 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005165
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005166 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005167 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03005168
Marcel Holtmann901801b2013-10-06 23:55:51 -07005169 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03005170}
Johan Hedberga88a9652011-03-30 13:18:12 +03005171
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005172void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5173 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03005174{
Johan Hedbergb644ba32012-01-17 21:48:47 +02005175 struct mgmt_ev_device_found *ev;
5176 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
5177 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03005178
Johan Hedbergb644ba32012-01-17 21:48:47 +02005179 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03005180
Johan Hedbergb644ba32012-01-17 21:48:47 +02005181 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03005182
Johan Hedbergb644ba32012-01-17 21:48:47 +02005183 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005184 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005185 ev->rssi = rssi;
5186
5187 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005188 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005189
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005190 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005191
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005192 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03005193}
Johan Hedberg314b2382011-04-27 10:29:57 -04005194
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005195void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04005196{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005197 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02005198 struct pending_cmd *cmd;
5199
Andre Guedes343fb142011-11-22 17:14:19 -03005200 BT_DBG("%s discovering %u", hdev->name, discovering);
5201
Johan Hedberg164a6e72011-11-01 17:06:44 +02005202 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005203 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005204 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005205 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005206
5207 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02005208 u8 type = hdev->discovery.type;
5209
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005210 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
5211 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02005212 mgmt_pending_remove(cmd);
5213 }
5214
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005215 memset(&ev, 0, sizeof(ev));
5216 ev.type = hdev->discovery.type;
5217 ev.discovering = discovering;
5218
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005219 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04005220}
Antti Julku5e762442011-08-25 16:48:02 +03005221
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005222int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005223{
5224 struct pending_cmd *cmd;
5225 struct mgmt_ev_device_blocked ev;
5226
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005227 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005228
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005229 bacpy(&ev.addr.bdaddr, bdaddr);
5230 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005231
Johan Hedberg744cf192011-11-08 20:40:14 +02005232 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005233 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005234}
5235
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005236int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005237{
5238 struct pending_cmd *cmd;
5239 struct mgmt_ev_device_unblocked ev;
5240
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005241 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005242
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005243 bacpy(&ev.addr.bdaddr, bdaddr);
5244 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005245
Johan Hedberg744cf192011-11-08 20:40:14 +02005246 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005247 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005248}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005249
5250static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5251{
5252 BT_DBG("%s status %u", hdev->name, status);
5253
5254 /* Clear the advertising mgmt setting if we failed to re-enable it */
5255 if (status) {
5256 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005257 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005258 }
5259}
5260
5261void mgmt_reenable_advertising(struct hci_dev *hdev)
5262{
5263 struct hci_request req;
5264
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005265 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005266 return;
5267
5268 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5269 return;
5270
5271 hci_req_init(&req, hdev);
5272 enable_advertising(&req);
5273
5274 /* If this fails we have no option but to let user space know
5275 * that we've disabled advertising.
5276 */
5277 if (hci_req_run(&req, adv_enable_complete) < 0) {
5278 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005279 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005280 }
5281}