blob: 4ee07b4323792c7712d44f48c96002101f85d6fb [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 */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200131 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200132 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
133 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
134 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
135 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
136 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
137 MGMT_STATUS_BUSY, /* Command Disallowed */
138 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
139 MGMT_STATUS_REJECTED, /* Rejected Security */
140 MGMT_STATUS_REJECTED, /* Rejected Personal */
141 MGMT_STATUS_TIMEOUT, /* Host Timeout */
142 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
143 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
144 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
145 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
146 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
147 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
148 MGMT_STATUS_BUSY, /* Repeated Attempts */
149 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
150 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
151 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
152 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
153 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
154 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
155 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
156 MGMT_STATUS_FAILED, /* Unspecified Error */
157 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
158 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
159 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
160 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
161 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
162 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
163 MGMT_STATUS_FAILED, /* Unit Link Key Used */
164 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
165 MGMT_STATUS_TIMEOUT, /* Instant Passed */
166 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
167 MGMT_STATUS_FAILED, /* Transaction Collision */
168 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
169 MGMT_STATUS_REJECTED, /* QoS Rejected */
170 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
171 MGMT_STATUS_REJECTED, /* Insufficient Security */
172 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
173 MGMT_STATUS_BUSY, /* Role Switch Pending */
174 MGMT_STATUS_FAILED, /* Slot Violation */
175 MGMT_STATUS_FAILED, /* Role Switch Failed */
176 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
177 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
178 MGMT_STATUS_BUSY, /* Host Busy Pairing */
179 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
180 MGMT_STATUS_BUSY, /* Controller Busy */
181 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
182 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
183 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
184 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
185 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
186};
187
188static u8 mgmt_status(u8 hci_status)
189{
190 if (hci_status < ARRAY_SIZE(mgmt_status_table))
191 return mgmt_status_table[hci_status];
192
193 return MGMT_STATUS_FAILED;
194}
195
Szymon Janc4e51eae2011-02-25 19:05:48 +0100196static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200197{
198 struct sk_buff *skb;
199 struct mgmt_hdr *hdr;
200 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300201 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200202
Szymon Janc34eb5252011-02-28 14:10:08 +0100203 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200204
Andre Guedes790eff42012-06-07 19:05:46 -0300205 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200206 if (!skb)
207 return -ENOMEM;
208
209 hdr = (void *) skb_put(skb, sizeof(*hdr));
210
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530211 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100212 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200213 hdr->len = cpu_to_le16(sizeof(*ev));
214
215 ev = (void *) skb_put(skb, sizeof(*ev));
216 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200217 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200218
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300219 err = sock_queue_rcv_skb(sk, skb);
220 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200221 kfree_skb(skb);
222
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300223 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200224}
225
Johan Hedbergaee9b212012-02-18 15:07:59 +0200226static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300227 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200228{
229 struct sk_buff *skb;
230 struct mgmt_hdr *hdr;
231 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300232 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200233
234 BT_DBG("sock %p", sk);
235
Andre Guedes790eff42012-06-07 19:05:46 -0300236 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200237 if (!skb)
238 return -ENOMEM;
239
240 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200241
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530242 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100243 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200244 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200247 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200248 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100249
250 if (rp)
251 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200252
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300253 err = sock_queue_rcv_skb(sk, skb);
254 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200255 kfree_skb(skb);
256
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100257 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200258}
259
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300260static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
261 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200262{
263 struct mgmt_rp_read_version rp;
264
265 BT_DBG("sock %p", sk);
266
267 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200268 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200269
Johan Hedbergaee9b212012-02-18 15:07:59 +0200270 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300271 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200272}
273
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300274static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
275 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200276{
277 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200278 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
279 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200280 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200281 size_t rp_size;
282 int i, err;
283
284 BT_DBG("sock %p", sk);
285
286 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
287
288 rp = kmalloc(rp_size, GFP_KERNEL);
289 if (!rp)
290 return -ENOMEM;
291
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200292 rp->num_commands = __constant_cpu_to_le16(num_commands);
293 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200294
295 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
296 put_unaligned_le16(mgmt_commands[i], opcode);
297
298 for (i = 0; i < num_events; i++, opcode++)
299 put_unaligned_le16(mgmt_events[i], opcode);
300
Johan Hedbergaee9b212012-02-18 15:07:59 +0200301 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300302 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200303 kfree(rp);
304
305 return err;
306}
307
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300308static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
309 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200310{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200311 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200312 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200313 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200314 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300315 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316
317 BT_DBG("sock %p", sk);
318
319 read_lock(&hci_dev_list_lock);
320
321 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300322 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700323 if (d->dev_type == HCI_BREDR)
324 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200325 }
326
Johan Hedberga38528f2011-01-22 06:46:43 +0200327 rp_len = sizeof(*rp) + (2 * count);
328 rp = kmalloc(rp_len, GFP_ATOMIC);
329 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100330 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200331 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100332 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200333
Johan Hedberg476e44c2012-10-19 20:10:46 +0300334 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200335 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200336 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200337 continue;
338
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700339 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
340 continue;
341
Marcel Holtmann1514b892013-10-06 08:25:01 -0700342 if (d->dev_type == HCI_BREDR) {
343 rp->index[count++] = cpu_to_le16(d->id);
344 BT_DBG("Added hci%u", d->id);
345 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200346 }
347
Johan Hedberg476e44c2012-10-19 20:10:46 +0300348 rp->num_controllers = cpu_to_le16(count);
349 rp_len = sizeof(*rp) + (2 * count);
350
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200351 read_unlock(&hci_dev_list_lock);
352
Johan Hedbergaee9b212012-02-18 15:07:59 +0200353 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300354 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200355
Johan Hedberga38528f2011-01-22 06:46:43 +0200356 kfree(rp);
357
358 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200359}
360
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200361static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200362{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200363 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200364
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_PAIRABLE;
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 Holtmann5afeac12014-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergaee9b212012-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 Hedbergf7b64e692010-12-13 21:07:06 +02001177
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001178 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +02001304 if (err < 0)
1305 mgmt_pending_remove(cmd);
1306
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001307failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001308 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-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 Hedberge8ba3a1f2013-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 Hedbergf7b64e692010-12-13 21:07:06 +02001457{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001458 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedberge8ba3a1f2013-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 Hedberg4ae143012013-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 Padovan6039aa72012-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 Hedbergaee9b212012-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{
Szymon Janc2763eda2011-03-22 13:12:22 +01003099 int err;
3100
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003101 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003102
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003103 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003104
Marcel Holtmannec109112014-01-10 02:07:30 -08003105 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3106 struct mgmt_cp_add_remote_oob_data *cp = data;
3107 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003108
Marcel Holtmannec109112014-01-10 02:07:30 -08003109 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
3110 cp->hash, cp->randomizer);
3111 if (err < 0)
3112 status = MGMT_STATUS_FAILED;
3113 else
3114 status = MGMT_STATUS_SUCCESS;
3115
3116 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3117 status, &cp->addr, sizeof(cp->addr));
3118 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3119 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
3120 u8 status;
3121
3122 err = hci_add_remote_oob_ext_data(hdev, &cp->addr.bdaddr,
3123 cp->hash192,
3124 cp->randomizer192,
3125 cp->hash256,
3126 cp->randomizer256);
3127 if (err < 0)
3128 status = MGMT_STATUS_FAILED;
3129 else
3130 status = MGMT_STATUS_SUCCESS;
3131
3132 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3133 status, &cp->addr, sizeof(cp->addr));
3134 } else {
3135 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
3136 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3137 MGMT_STATUS_INVALID_PARAMS);
3138 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003139
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003140 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003141 return err;
3142}
3143
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003144static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003145 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003146{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003147 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003148 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003149 int err;
3150
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003151 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003152
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003153 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003154
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003155 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003156 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003157 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003158 else
Szymon Janca6785be2012-12-13 15:11:21 +01003159 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003160
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003161 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003162 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003163
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003164 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003165 return err;
3166}
3167
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003168static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3169{
3170 struct pending_cmd *cmd;
3171 u8 type;
3172 int err;
3173
3174 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3175
3176 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3177 if (!cmd)
3178 return -ENOENT;
3179
3180 type = hdev->discovery.type;
3181
3182 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3183 &type, sizeof(type));
3184 mgmt_pending_remove(cmd);
3185
3186 return err;
3187}
3188
Andre Guedes7c307722013-04-30 15:29:28 -03003189static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3190{
3191 BT_DBG("status %d", status);
3192
3193 if (status) {
3194 hci_dev_lock(hdev);
3195 mgmt_start_discovery_failed(hdev, status);
3196 hci_dev_unlock(hdev);
3197 return;
3198 }
3199
3200 hci_dev_lock(hdev);
3201 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3202 hci_dev_unlock(hdev);
3203
3204 switch (hdev->discovery.type) {
3205 case DISCOV_TYPE_LE:
3206 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003207 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003208 break;
3209
3210 case DISCOV_TYPE_INTERLEAVED:
3211 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003212 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003213 break;
3214
3215 case DISCOV_TYPE_BREDR:
3216 break;
3217
3218 default:
3219 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3220 }
3221}
3222
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003223static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003224 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003225{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003226 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003227 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003228 struct hci_cp_le_set_scan_param param_cp;
3229 struct hci_cp_le_set_scan_enable enable_cp;
3230 struct hci_cp_inquiry inq_cp;
3231 struct hci_request req;
3232 /* General inquiry access code (GIAC) */
3233 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003234 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003235 int err;
3236
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003237 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003238
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003239 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003240
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003241 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003242 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003243 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003244 goto failed;
3245 }
3246
Andre Guedes642be6c2012-03-21 00:03:37 -03003247 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3248 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3249 MGMT_STATUS_BUSY);
3250 goto failed;
3251 }
3252
Johan Hedbergff9ef572012-01-04 14:23:45 +02003253 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003254 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003255 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003256 goto failed;
3257 }
3258
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003259 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003260 if (!cmd) {
3261 err = -ENOMEM;
3262 goto failed;
3263 }
3264
Andre Guedes4aab14e2012-02-17 20:39:36 -03003265 hdev->discovery.type = cp->type;
3266
Andre Guedes7c307722013-04-30 15:29:28 -03003267 hci_req_init(&req, hdev);
3268
Andre Guedes4aab14e2012-02-17 20:39:36 -03003269 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003270 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003271 status = mgmt_bredr_support(hdev);
3272 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003273 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003274 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003275 mgmt_pending_remove(cmd);
3276 goto failed;
3277 }
3278
Andre Guedes7c307722013-04-30 15:29:28 -03003279 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3280 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3281 MGMT_STATUS_BUSY);
3282 mgmt_pending_remove(cmd);
3283 goto failed;
3284 }
3285
3286 hci_inquiry_cache_flush(hdev);
3287
3288 memset(&inq_cp, 0, sizeof(inq_cp));
3289 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003290 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003291 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003292 break;
3293
3294 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003295 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003296 status = mgmt_le_support(hdev);
3297 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003298 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003299 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003300 mgmt_pending_remove(cmd);
3301 goto failed;
3302 }
3303
Andre Guedes7c307722013-04-30 15:29:28 -03003304 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003305 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003306 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3307 MGMT_STATUS_NOT_SUPPORTED);
3308 mgmt_pending_remove(cmd);
3309 goto failed;
3310 }
3311
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003312 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003313 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3314 MGMT_STATUS_REJECTED);
3315 mgmt_pending_remove(cmd);
3316 goto failed;
3317 }
3318
3319 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3320 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3321 MGMT_STATUS_BUSY);
3322 mgmt_pending_remove(cmd);
3323 goto failed;
3324 }
3325
3326 memset(&param_cp, 0, sizeof(param_cp));
3327 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003328 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3329 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmann79830f62013-10-18 16:38:09 -07003330 param_cp.own_address_type = hdev->own_addr_type;
Andre Guedes7c307722013-04-30 15:29:28 -03003331 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3332 &param_cp);
3333
3334 memset(&enable_cp, 0, sizeof(enable_cp));
3335 enable_cp.enable = LE_SCAN_ENABLE;
3336 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3337 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3338 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003339 break;
3340
Andre Guedesf39799f2012-02-17 20:39:35 -03003341 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003342 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3343 MGMT_STATUS_INVALID_PARAMS);
3344 mgmt_pending_remove(cmd);
3345 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003346 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003347
Andre Guedes7c307722013-04-30 15:29:28 -03003348 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003349 if (err < 0)
3350 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003351 else
3352 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003353
3354failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003355 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003356 return err;
3357}
3358
Andre Guedes1183fdc2013-04-30 15:29:35 -03003359static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3360{
3361 struct pending_cmd *cmd;
3362 int err;
3363
3364 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3365 if (!cmd)
3366 return -ENOENT;
3367
3368 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3369 &hdev->discovery.type, sizeof(hdev->discovery.type));
3370 mgmt_pending_remove(cmd);
3371
3372 return err;
3373}
3374
Andre Guedes0e05bba2013-04-30 15:29:33 -03003375static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3376{
3377 BT_DBG("status %d", status);
3378
3379 hci_dev_lock(hdev);
3380
3381 if (status) {
3382 mgmt_stop_discovery_failed(hdev, status);
3383 goto unlock;
3384 }
3385
3386 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3387
3388unlock:
3389 hci_dev_unlock(hdev);
3390}
3391
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003392static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003393 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003394{
Johan Hedbergd9306502012-02-20 23:25:18 +02003395 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003396 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003397 struct hci_cp_remote_name_req_cancel cp;
3398 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003399 struct hci_request req;
3400 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003401 int err;
3402
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003403 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003404
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003405 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003406
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003407 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003408 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003409 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3410 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003411 goto unlock;
3412 }
3413
3414 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003415 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003416 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3417 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003418 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003419 }
3420
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003421 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003422 if (!cmd) {
3423 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003424 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003425 }
3426
Andre Guedes0e05bba2013-04-30 15:29:33 -03003427 hci_req_init(&req, hdev);
3428
Andre Guedese0d9727e2012-03-20 15:15:36 -03003429 switch (hdev->discovery.state) {
3430 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003431 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3432 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3433 } else {
3434 cancel_delayed_work(&hdev->le_scan_disable);
3435
3436 memset(&enable_cp, 0, sizeof(enable_cp));
3437 enable_cp.enable = LE_SCAN_DISABLE;
3438 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3439 sizeof(enable_cp), &enable_cp);
3440 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003441
Andre Guedese0d9727e2012-03-20 15:15:36 -03003442 break;
3443
3444 case DISCOVERY_RESOLVING:
3445 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003446 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003447 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003448 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003449 err = cmd_complete(sk, hdev->id,
3450 MGMT_OP_STOP_DISCOVERY, 0,
3451 &mgmt_cp->type,
3452 sizeof(mgmt_cp->type));
3453 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3454 goto unlock;
3455 }
3456
3457 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003458 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3459 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003460
3461 break;
3462
3463 default:
3464 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003465
3466 mgmt_pending_remove(cmd);
3467 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3468 MGMT_STATUS_FAILED, &mgmt_cp->type,
3469 sizeof(mgmt_cp->type));
3470 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003471 }
3472
Andre Guedes0e05bba2013-04-30 15:29:33 -03003473 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003474 if (err < 0)
3475 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003476 else
3477 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003478
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003479unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003480 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003481 return err;
3482}
3483
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003484static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003485 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003486{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003487 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003488 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003489 int err;
3490
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003491 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003492
Johan Hedberg561aafb2012-01-04 13:31:59 +02003493 hci_dev_lock(hdev);
3494
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003495 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003496 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003497 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003498 goto failed;
3499 }
3500
Johan Hedberga198e7b2012-02-17 14:27:06 +02003501 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003502 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003503 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003504 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003505 goto failed;
3506 }
3507
3508 if (cp->name_known) {
3509 e->name_state = NAME_KNOWN;
3510 list_del(&e->list);
3511 } else {
3512 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02003513 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003514 }
3515
Johan Hedberge3846622013-01-09 15:29:33 +02003516 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3517 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003518
3519failed:
3520 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003521 return err;
3522}
3523
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003524static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003525 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003526{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003527 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003528 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003529 int err;
3530
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003531 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003532
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003533 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003534 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3535 MGMT_STATUS_INVALID_PARAMS,
3536 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003537
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003538 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003539
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003540 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003541 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003542 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003543 else
Szymon Janca6785be2012-12-13 15:11:21 +01003544 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003545
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003546 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003547 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003548
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003549 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003550
3551 return err;
3552}
3553
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003554static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003555 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003556{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003557 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003558 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003559 int err;
3560
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003561 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003562
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003563 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003564 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3565 MGMT_STATUS_INVALID_PARAMS,
3566 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003567
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003568 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003569
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003570 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003571 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003572 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003573 else
Szymon Janca6785be2012-12-13 15:11:21 +01003574 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003575
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003576 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003577 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003578
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003579 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003580
3581 return err;
3582}
3583
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003584static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3585 u16 len)
3586{
3587 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003588 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003589 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003590 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003591
3592 BT_DBG("%s", hdev->name);
3593
Szymon Jancc72d4b82012-03-16 16:02:57 +01003594 source = __le16_to_cpu(cp->source);
3595
3596 if (source > 0x0002)
3597 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3598 MGMT_STATUS_INVALID_PARAMS);
3599
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003600 hci_dev_lock(hdev);
3601
Szymon Jancc72d4b82012-03-16 16:02:57 +01003602 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003603 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3604 hdev->devid_product = __le16_to_cpu(cp->product);
3605 hdev->devid_version = __le16_to_cpu(cp->version);
3606
3607 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3608
Johan Hedberg890ea892013-03-15 17:06:52 -05003609 hci_req_init(&req, hdev);
3610 update_eir(&req);
3611 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003612
3613 hci_dev_unlock(hdev);
3614
3615 return err;
3616}
3617
Johan Hedberg4375f102013-09-25 13:26:10 +03003618static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3619{
3620 struct cmd_lookup match = { NULL, hdev };
3621
3622 if (status) {
3623 u8 mgmt_err = mgmt_status(status);
3624
3625 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3626 cmd_status_rsp, &mgmt_err);
3627 return;
3628 }
3629
3630 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3631 &match);
3632
3633 new_settings(hdev, match.sk);
3634
3635 if (match.sk)
3636 sock_put(match.sk);
3637}
3638
Marcel Holtmann21b51872013-10-10 09:47:53 -07003639static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3640 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003641{
3642 struct mgmt_mode *cp = data;
3643 struct pending_cmd *cmd;
3644 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003645 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003646 int err;
3647
3648 BT_DBG("request for %s", hdev->name);
3649
Johan Hedberge6fe7982013-10-02 15:45:22 +03003650 status = mgmt_le_support(hdev);
3651 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003652 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003653 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003654
3655 if (cp->val != 0x00 && cp->val != 0x01)
3656 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3657 MGMT_STATUS_INVALID_PARAMS);
3658
3659 hci_dev_lock(hdev);
3660
3661 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003662 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003663
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003664 /* The following conditions are ones which mean that we should
3665 * not do any HCI communication but directly send a mgmt
3666 * response to user space (after toggling the flag if
3667 * necessary).
3668 */
3669 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003670 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003671 bool changed = false;
3672
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003673 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3674 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003675 changed = true;
3676 }
3677
3678 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3679 if (err < 0)
3680 goto unlock;
3681
3682 if (changed)
3683 err = new_settings(hdev, sk);
3684
3685 goto unlock;
3686 }
3687
3688 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3689 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3690 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3691 MGMT_STATUS_BUSY);
3692 goto unlock;
3693 }
3694
3695 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3696 if (!cmd) {
3697 err = -ENOMEM;
3698 goto unlock;
3699 }
3700
3701 hci_req_init(&req, hdev);
3702
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003703 if (val)
3704 enable_advertising(&req);
3705 else
3706 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003707
3708 err = hci_req_run(&req, set_advertising_complete);
3709 if (err < 0)
3710 mgmt_pending_remove(cmd);
3711
3712unlock:
3713 hci_dev_unlock(hdev);
3714 return err;
3715}
3716
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003717static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3718 void *data, u16 len)
3719{
3720 struct mgmt_cp_set_static_address *cp = data;
3721 int err;
3722
3723 BT_DBG("%s", hdev->name);
3724
Marcel Holtmann62af4442013-10-02 22:10:32 -07003725 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003726 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003727 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003728
3729 if (hdev_is_powered(hdev))
3730 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3731 MGMT_STATUS_REJECTED);
3732
3733 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3734 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3735 return cmd_status(sk, hdev->id,
3736 MGMT_OP_SET_STATIC_ADDRESS,
3737 MGMT_STATUS_INVALID_PARAMS);
3738
3739 /* Two most significant bits shall be set */
3740 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3741 return cmd_status(sk, hdev->id,
3742 MGMT_OP_SET_STATIC_ADDRESS,
3743 MGMT_STATUS_INVALID_PARAMS);
3744 }
3745
3746 hci_dev_lock(hdev);
3747
3748 bacpy(&hdev->static_addr, &cp->bdaddr);
3749
3750 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3751
3752 hci_dev_unlock(hdev);
3753
3754 return err;
3755}
3756
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003757static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3758 void *data, u16 len)
3759{
3760 struct mgmt_cp_set_scan_params *cp = data;
3761 __u16 interval, window;
3762 int err;
3763
3764 BT_DBG("%s", hdev->name);
3765
3766 if (!lmp_le_capable(hdev))
3767 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3768 MGMT_STATUS_NOT_SUPPORTED);
3769
3770 interval = __le16_to_cpu(cp->interval);
3771
3772 if (interval < 0x0004 || interval > 0x4000)
3773 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3774 MGMT_STATUS_INVALID_PARAMS);
3775
3776 window = __le16_to_cpu(cp->window);
3777
3778 if (window < 0x0004 || window > 0x4000)
3779 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3780 MGMT_STATUS_INVALID_PARAMS);
3781
Marcel Holtmann899e1072013-10-14 09:55:32 -07003782 if (window > interval)
3783 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3784 MGMT_STATUS_INVALID_PARAMS);
3785
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003786 hci_dev_lock(hdev);
3787
3788 hdev->le_scan_interval = interval;
3789 hdev->le_scan_window = window;
3790
3791 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3792
3793 hci_dev_unlock(hdev);
3794
3795 return err;
3796}
3797
Johan Hedberg33e38b32013-03-15 17:07:05 -05003798static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3799{
3800 struct pending_cmd *cmd;
3801
3802 BT_DBG("status 0x%02x", status);
3803
3804 hci_dev_lock(hdev);
3805
3806 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3807 if (!cmd)
3808 goto unlock;
3809
3810 if (status) {
3811 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3812 mgmt_status(status));
3813 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003814 struct mgmt_mode *cp = cmd->param;
3815
3816 if (cp->val)
3817 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3818 else
3819 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3820
Johan Hedberg33e38b32013-03-15 17:07:05 -05003821 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3822 new_settings(hdev, cmd->sk);
3823 }
3824
3825 mgmt_pending_remove(cmd);
3826
3827unlock:
3828 hci_dev_unlock(hdev);
3829}
3830
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003831static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003832 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003833{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003834 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003835 struct pending_cmd *cmd;
3836 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003837 int err;
3838
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003839 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003840
Johan Hedberg56f87902013-10-02 13:43:13 +03003841 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3842 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003843 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3844 MGMT_STATUS_NOT_SUPPORTED);
3845
Johan Hedberga7e80f22013-01-09 16:05:19 +02003846 if (cp->val != 0x00 && cp->val != 0x01)
3847 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3848 MGMT_STATUS_INVALID_PARAMS);
3849
Johan Hedberg5400c042012-02-21 16:40:33 +02003850 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003851 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003852 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003853
3854 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003855 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003856 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003857
3858 hci_dev_lock(hdev);
3859
Johan Hedberg05cbf292013-03-15 17:07:07 -05003860 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3861 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3862 MGMT_STATUS_BUSY);
3863 goto unlock;
3864 }
3865
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003866 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3867 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3868 hdev);
3869 goto unlock;
3870 }
3871
Johan Hedberg33e38b32013-03-15 17:07:05 -05003872 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3873 data, len);
3874 if (!cmd) {
3875 err = -ENOMEM;
3876 goto unlock;
3877 }
3878
3879 hci_req_init(&req, hdev);
3880
Johan Hedberg406d7802013-03-15 17:07:09 -05003881 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003882
3883 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003884 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003885 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003886 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003887 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003888 }
3889
Johan Hedberg33e38b32013-03-15 17:07:05 -05003890unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003891 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003892
Antti Julkuf6422ec2011-06-22 13:11:56 +03003893 return err;
3894}
3895
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003896static void set_bredr_scan(struct hci_request *req)
3897{
3898 struct hci_dev *hdev = req->hdev;
3899 u8 scan = 0;
3900
3901 /* Ensure that fast connectable is disabled. This function will
3902 * not do anything if the page scan parameters are already what
3903 * they should be.
3904 */
3905 write_fast_connectable(req, false);
3906
3907 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3908 scan |= SCAN_PAGE;
3909 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3910 scan |= SCAN_INQUIRY;
3911
3912 if (scan)
3913 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3914}
3915
Johan Hedberg0663ca22013-10-02 13:43:14 +03003916static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3917{
3918 struct pending_cmd *cmd;
3919
3920 BT_DBG("status 0x%02x", status);
3921
3922 hci_dev_lock(hdev);
3923
3924 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3925 if (!cmd)
3926 goto unlock;
3927
3928 if (status) {
3929 u8 mgmt_err = mgmt_status(status);
3930
3931 /* We need to restore the flag if related HCI commands
3932 * failed.
3933 */
3934 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3935
3936 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3937 } else {
3938 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3939 new_settings(hdev, cmd->sk);
3940 }
3941
3942 mgmt_pending_remove(cmd);
3943
3944unlock:
3945 hci_dev_unlock(hdev);
3946}
3947
3948static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3949{
3950 struct mgmt_mode *cp = data;
3951 struct pending_cmd *cmd;
3952 struct hci_request req;
3953 int err;
3954
3955 BT_DBG("request for %s", hdev->name);
3956
3957 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3958 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3959 MGMT_STATUS_NOT_SUPPORTED);
3960
3961 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3962 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3963 MGMT_STATUS_REJECTED);
3964
3965 if (cp->val != 0x00 && cp->val != 0x01)
3966 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3967 MGMT_STATUS_INVALID_PARAMS);
3968
3969 hci_dev_lock(hdev);
3970
3971 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3972 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3973 goto unlock;
3974 }
3975
3976 if (!hdev_is_powered(hdev)) {
3977 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003978 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3979 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3980 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3981 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3982 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3983 }
3984
3985 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3986
3987 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3988 if (err < 0)
3989 goto unlock;
3990
3991 err = new_settings(hdev, sk);
3992 goto unlock;
3993 }
3994
3995 /* Reject disabling when powered on */
3996 if (!cp->val) {
3997 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3998 MGMT_STATUS_REJECTED);
3999 goto unlock;
4000 }
4001
4002 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
4003 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4004 MGMT_STATUS_BUSY);
4005 goto unlock;
4006 }
4007
4008 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4009 if (!cmd) {
4010 err = -ENOMEM;
4011 goto unlock;
4012 }
4013
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004014 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03004015 * generates the correct flags.
4016 */
4017 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4018
4019 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004020
4021 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4022 set_bredr_scan(&req);
4023
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004024 /* Since only the advertising data flags will change, there
4025 * is no need to update the scan response data.
4026 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004027 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004028
Johan Hedberg0663ca22013-10-02 13:43:14 +03004029 err = hci_req_run(&req, set_bredr_complete);
4030 if (err < 0)
4031 mgmt_pending_remove(cmd);
4032
4033unlock:
4034 hci_dev_unlock(hdev);
4035 return err;
4036}
4037
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004038static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4039 void *data, u16 len)
4040{
4041 struct mgmt_mode *cp = data;
4042 struct pending_cmd *cmd;
4043 u8 status;
4044 int err;
4045
4046 BT_DBG("request for %s", hdev->name);
4047
4048 status = mgmt_bredr_support(hdev);
4049 if (status)
4050 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4051 status);
4052
Marcel Holtmann5afeac12014-01-10 02:07:27 -08004053 if (!lmp_sc_capable(hdev) &&
4054 !test_bit(HCI_FORCE_SC, &hdev->dev_flags))
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004055 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4056 MGMT_STATUS_NOT_SUPPORTED);
4057
4058 if (cp->val != 0x00 && cp->val != 0x01)
4059 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4060 MGMT_STATUS_INVALID_PARAMS);
4061
4062 hci_dev_lock(hdev);
4063
4064 if (!hdev_is_powered(hdev)) {
4065 bool changed;
4066
4067 if (cp->val)
4068 changed = !test_and_set_bit(HCI_SC_ENABLED,
4069 &hdev->dev_flags);
4070 else
4071 changed = test_and_clear_bit(HCI_SC_ENABLED,
4072 &hdev->dev_flags);
4073
4074 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4075 if (err < 0)
4076 goto failed;
4077
4078 if (changed)
4079 err = new_settings(hdev, sk);
4080
4081 goto failed;
4082 }
4083
4084 if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
4085 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4086 MGMT_STATUS_BUSY);
4087 goto failed;
4088 }
4089
4090 if (!!cp->val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
4091 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4092 goto failed;
4093 }
4094
4095 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4096 if (!cmd) {
4097 err = -ENOMEM;
4098 goto failed;
4099 }
4100
4101 err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &cp->val);
4102 if (err < 0) {
4103 mgmt_pending_remove(cmd);
4104 goto failed;
4105 }
4106
4107failed:
4108 hci_dev_unlock(hdev);
4109 return err;
4110}
4111
Johan Hedberg3f706b72013-01-20 14:27:16 +02004112static bool ltk_is_valid(struct mgmt_ltk_info *key)
4113{
Johan Hedberg44b20d32013-01-20 14:27:17 +02004114 if (key->authenticated != 0x00 && key->authenticated != 0x01)
4115 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004116 if (key->master != 0x00 && key->master != 0x01)
4117 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004118 if (!bdaddr_type_is_le(key->addr.type))
4119 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004120 return true;
4121}
4122
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004123static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004124 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004125{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004126 struct mgmt_cp_load_long_term_keys *cp = cp_data;
4127 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004128 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004129
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004130 BT_DBG("request for %s", hdev->name);
4131
4132 if (!lmp_le_capable(hdev))
4133 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4134 MGMT_STATUS_NOT_SUPPORTED);
4135
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004136 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004137
4138 expected_len = sizeof(*cp) + key_count *
4139 sizeof(struct mgmt_ltk_info);
4140 if (expected_len != len) {
4141 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004142 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004143 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02004144 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004145 }
4146
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004147 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004148
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004149 for (i = 0; i < key_count; i++) {
4150 struct mgmt_ltk_info *key = &cp->keys[i];
4151
Johan Hedberg3f706b72013-01-20 14:27:16 +02004152 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004153 return cmd_status(sk, hdev->id,
4154 MGMT_OP_LOAD_LONG_TERM_KEYS,
4155 MGMT_STATUS_INVALID_PARAMS);
4156 }
4157
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004158 hci_dev_lock(hdev);
4159
4160 hci_smp_ltks_clear(hdev);
4161
4162 for (i = 0; i < key_count; i++) {
4163 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004164 u8 type, addr_type;
4165
4166 if (key->addr.type == BDADDR_LE_PUBLIC)
4167 addr_type = ADDR_LE_DEV_PUBLIC;
4168 else
4169 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004170
4171 if (key->master)
4172 type = HCI_SMP_LTK;
4173 else
4174 type = HCI_SMP_LTK_SLAVE;
4175
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004176 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004177 type, 0, key->authenticated, key->val,
4178 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004179 }
4180
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004181 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4182 NULL, 0);
4183
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004184 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004185
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004186 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004187}
4188
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004189static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004190 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4191 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004192 bool var_len;
4193 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004194} mgmt_handlers[] = {
4195 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004196 { read_version, false, MGMT_READ_VERSION_SIZE },
4197 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4198 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4199 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4200 { set_powered, false, MGMT_SETTING_SIZE },
4201 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4202 { set_connectable, false, MGMT_SETTING_SIZE },
4203 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4204 { set_pairable, false, MGMT_SETTING_SIZE },
4205 { set_link_security, false, MGMT_SETTING_SIZE },
4206 { set_ssp, false, MGMT_SETTING_SIZE },
4207 { set_hs, false, MGMT_SETTING_SIZE },
4208 { set_le, false, MGMT_SETTING_SIZE },
4209 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4210 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4211 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4212 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4213 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4214 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4215 { disconnect, false, MGMT_DISCONNECT_SIZE },
4216 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4217 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4218 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4219 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4220 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4221 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4222 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4223 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4224 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4225 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4226 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4227 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
Marcel Holtmannec109112014-01-10 02:07:30 -08004228 { add_remote_oob_data, true, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
Johan Hedbergbe22b542012-03-01 22:24:41 +02004229 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4230 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4231 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4232 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4233 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4234 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004235 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004236 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004237 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004238 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004239 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004240 { set_secure_conn, false, MGMT_SETTING_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004241};
4242
4243
Johan Hedberg03811012010-12-08 00:21:06 +02004244int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4245{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004246 void *buf;
4247 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004248 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004249 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004250 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004251 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004252 int err;
4253
4254 BT_DBG("got %zu bytes", msglen);
4255
4256 if (msglen < sizeof(*hdr))
4257 return -EINVAL;
4258
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004259 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004260 if (!buf)
4261 return -ENOMEM;
4262
4263 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4264 err = -EFAULT;
4265 goto done;
4266 }
4267
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004268 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004269 opcode = __le16_to_cpu(hdr->opcode);
4270 index = __le16_to_cpu(hdr->index);
4271 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004272
4273 if (len != msglen - sizeof(*hdr)) {
4274 err = -EINVAL;
4275 goto done;
4276 }
4277
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004278 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004279 hdev = hci_dev_get(index);
4280 if (!hdev) {
4281 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004282 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004283 goto done;
4284 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004285
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004286 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4287 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004288 err = cmd_status(sk, index, opcode,
4289 MGMT_STATUS_INVALID_INDEX);
4290 goto done;
4291 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004292 }
4293
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004294 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004295 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004296 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004297 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004298 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004299 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004300 }
4301
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004302 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004303 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004304 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004305 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004306 goto done;
4307 }
4308
Johan Hedbergbe22b542012-03-01 22:24:41 +02004309 handler = &mgmt_handlers[opcode];
4310
4311 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004312 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004313 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004314 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004315 goto done;
4316 }
4317
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004318 if (hdev)
4319 mgmt_init_hdev(sk, hdev);
4320
4321 cp = buf + sizeof(*hdr);
4322
Johan Hedbergbe22b542012-03-01 22:24:41 +02004323 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004324 if (err < 0)
4325 goto done;
4326
Johan Hedberg03811012010-12-08 00:21:06 +02004327 err = msglen;
4328
4329done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004330 if (hdev)
4331 hci_dev_put(hdev);
4332
Johan Hedberg03811012010-12-08 00:21:06 +02004333 kfree(buf);
4334 return err;
4335}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004336
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004337void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004338{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004339 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004340 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004341
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004342 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004343}
4344
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004345void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004346{
Johan Hedberg5f159032012-03-02 03:13:19 +02004347 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004348
Marcel Holtmann1514b892013-10-06 08:25:01 -07004349 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004350 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004351
Johan Hedberg744cf192011-11-08 20:40:14 +02004352 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004353
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004354 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004355}
4356
Johan Hedberg229ab392013-03-15 17:06:53 -05004357static void powered_complete(struct hci_dev *hdev, u8 status)
4358{
4359 struct cmd_lookup match = { NULL, hdev };
4360
4361 BT_DBG("status 0x%02x", status);
4362
4363 hci_dev_lock(hdev);
4364
4365 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4366
4367 new_settings(hdev, match.sk);
4368
4369 hci_dev_unlock(hdev);
4370
4371 if (match.sk)
4372 sock_put(match.sk);
4373}
4374
Johan Hedberg70da6242013-03-15 17:06:51 -05004375static int powered_update_hci(struct hci_dev *hdev)
4376{
Johan Hedberg890ea892013-03-15 17:06:52 -05004377 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004378 u8 link_sec;
4379
Johan Hedberg890ea892013-03-15 17:06:52 -05004380 hci_req_init(&req, hdev);
4381
Johan Hedberg70da6242013-03-15 17:06:51 -05004382 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4383 !lmp_host_ssp_capable(hdev)) {
4384 u8 ssp = 1;
4385
Johan Hedberg890ea892013-03-15 17:06:52 -05004386 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004387 }
4388
Johan Hedbergc73eee92013-04-19 18:35:21 +03004389 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4390 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004391 struct hci_cp_write_le_host_supported cp;
4392
4393 cp.le = 1;
4394 cp.simul = lmp_le_br_capable(hdev);
4395
4396 /* Check first if we already have the right
4397 * host state (host features set)
4398 */
4399 if (cp.le != lmp_host_le_capable(hdev) ||
4400 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004401 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4402 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004403 }
4404
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004405 if (lmp_le_capable(hdev)) {
4406 /* Set random address to static address if configured */
4407 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4408 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4409 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004410
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004411 /* Make sure the controller has a good default for
4412 * advertising data. This also applies to the case
4413 * where BR/EDR was toggled during the AUTO_OFF phase.
4414 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004415 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004416 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004417 update_scan_rsp_data(&req);
4418 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004419
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004420 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4421 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004422 }
4423
Johan Hedberg70da6242013-03-15 17:06:51 -05004424 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4425 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004426 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4427 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004428
4429 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004430 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4431 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004432 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004433 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004434 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004435 }
4436
Johan Hedberg229ab392013-03-15 17:06:53 -05004437 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004438}
4439
Johan Hedberg744cf192011-11-08 20:40:14 +02004440int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004441{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004442 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004443 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4444 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004445 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004446
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004447 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4448 return 0;
4449
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004450 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004451 if (powered_update_hci(hdev) == 0)
4452 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004453
Johan Hedberg229ab392013-03-15 17:06:53 -05004454 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4455 &match);
4456 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004457 }
4458
Johan Hedberg229ab392013-03-15 17:06:53 -05004459 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4460 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4461
4462 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4463 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4464 zero_cod, sizeof(zero_cod), NULL);
4465
4466new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004467 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004468
4469 if (match.sk)
4470 sock_put(match.sk);
4471
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004472 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004473}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004474
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004475void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004476{
4477 struct pending_cmd *cmd;
4478 u8 status;
4479
4480 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4481 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004482 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004483
4484 if (err == -ERFKILL)
4485 status = MGMT_STATUS_RFKILLED;
4486 else
4487 status = MGMT_STATUS_FAILED;
4488
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004489 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004490
4491 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004492}
4493
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004494void mgmt_discoverable_timeout(struct hci_dev *hdev)
4495{
4496 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004497
4498 hci_dev_lock(hdev);
4499
4500 /* When discoverable timeout triggers, then just make sure
4501 * the limited discoverable flag is cleared. Even in the case
4502 * of a timeout triggered from general discoverable, it is
4503 * safe to unconditionally clear the flag.
4504 */
4505 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004506 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004507
4508 hci_req_init(&req, hdev);
Johan Hedberg4b580612013-10-19 23:38:21 +03004509 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4510 u8 scan = SCAN_PAGE;
4511 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
4512 sizeof(scan), &scan);
4513 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004514 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004515 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004516 hci_req_run(&req, NULL);
4517
4518 hdev->discov_timeout = 0;
4519
Johan Hedberg9a43e252013-10-20 19:00:07 +03004520 new_settings(hdev, NULL);
4521
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004522 hci_dev_unlock(hdev);
4523}
4524
Marcel Holtmann86a75642013-10-15 06:33:54 -07004525void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004526{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004527 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004528
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004529 /* Nothing needed here if there's a pending command since that
4530 * commands request completion callback takes care of everything
4531 * necessary.
4532 */
4533 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004534 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004535
Johan Hedberg9a43e252013-10-20 19:00:07 +03004536 if (discoverable) {
Marcel Holtmann86a75642013-10-15 06:33:54 -07004537 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004538 } else {
4539 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmann86a75642013-10-15 06:33:54 -07004540 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004541 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004542
Johan Hedberg9a43e252013-10-20 19:00:07 +03004543 if (changed) {
4544 struct hci_request req;
4545
4546 /* In case this change in discoverable was triggered by
4547 * a disabling of connectable there could be a need to
4548 * update the advertising flags.
4549 */
4550 hci_req_init(&req, hdev);
4551 update_adv_data(&req);
4552 hci_req_run(&req, NULL);
4553
Marcel Holtmann86a75642013-10-15 06:33:54 -07004554 new_settings(hdev, NULL);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004555 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004556}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004557
Marcel Holtmanna3309162013-10-15 06:33:55 -07004558void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004559{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004560 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004561
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004562 /* Nothing needed here if there's a pending command since that
4563 * commands request completion callback takes care of everything
4564 * necessary.
4565 */
4566 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004567 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004568
Marcel Holtmanna3309162013-10-15 06:33:55 -07004569 if (connectable)
4570 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4571 else
4572 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004573
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004574 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004575 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004576}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004577
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004578void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004579{
Johan Hedbergca69b792011-11-11 18:10:00 +02004580 u8 mgmt_err = mgmt_status(status);
4581
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004582 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004583 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004584 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004585
4586 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004587 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004588 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004589}
4590
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004591void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4592 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004593{
Johan Hedberg86742e12011-11-07 23:13:38 +02004594 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004595
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004596 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004597
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004598 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004599 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004600 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004601 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004602 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004603 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004604
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004605 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004606}
Johan Hedbergf7520542011-01-20 12:34:39 +02004607
Marcel Holtmann083368f2013-10-15 14:26:29 -07004608void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004609{
4610 struct mgmt_ev_new_long_term_key ev;
4611
4612 memset(&ev, 0, sizeof(ev));
4613
4614 ev.store_hint = persistent;
4615 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004616 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004617 ev.key.authenticated = key->authenticated;
4618 ev.key.enc_size = key->enc_size;
4619 ev.key.ediv = key->ediv;
4620
4621 if (key->type == HCI_SMP_LTK)
4622 ev.key.master = 1;
4623
4624 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4625 memcpy(ev.key.val, key->val, sizeof(key->val));
4626
Marcel Holtmann083368f2013-10-15 14:26:29 -07004627 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004628}
4629
Marcel Holtmann94933992013-10-15 10:26:39 -07004630static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4631 u8 data_len)
4632{
4633 eir[eir_len++] = sizeof(type) + data_len;
4634 eir[eir_len++] = type;
4635 memcpy(&eir[eir_len], data, data_len);
4636 eir_len += data_len;
4637
4638 return eir_len;
4639}
4640
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004641void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4642 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4643 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004644{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004645 char buf[512];
4646 struct mgmt_ev_device_connected *ev = (void *) buf;
4647 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004648
Johan Hedbergb644ba32012-01-17 21:48:47 +02004649 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004650 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004651
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004652 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004653
Johan Hedbergb644ba32012-01-17 21:48:47 +02004654 if (name_len > 0)
4655 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004656 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004657
4658 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004659 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004660 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004661
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004662 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004663
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004664 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4665 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004666}
4667
Johan Hedberg8962ee72011-01-20 12:40:27 +02004668static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4669{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004670 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004671 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004672 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004673
Johan Hedberg88c3df12012-02-09 14:27:38 +02004674 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4675 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004676
Johan Hedbergaee9b212012-02-18 15:07:59 +02004677 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004678 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004679
4680 *sk = cmd->sk;
4681 sock_hold(*sk);
4682
Johan Hedberga664b5b2011-02-19 12:06:02 -03004683 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004684}
4685
Johan Hedberg124f6e32012-02-09 13:50:12 +02004686static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004687{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004688 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004689 struct mgmt_cp_unpair_device *cp = cmd->param;
4690 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004691
4692 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004693 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4694 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004695
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004696 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4697
Johan Hedbergaee9b212012-02-18 15:07:59 +02004698 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004699
4700 mgmt_pending_remove(cmd);
4701}
4702
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004703void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4704 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004705{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004706 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004707 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004708
Andre Guedes57eb7762013-10-30 19:01:41 -03004709 if (link_type != ACL_LINK && link_type != LE_LINK)
4710 return;
4711
Johan Hedberg744cf192011-11-08 20:40:14 +02004712 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004713
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004714 bacpy(&ev.addr.bdaddr, bdaddr);
4715 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4716 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004717
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004718 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004719
4720 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004721 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004722
Johan Hedberg124f6e32012-02-09 13:50:12 +02004723 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004724 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004725}
4726
Marcel Holtmann78929242013-10-06 23:55:47 -07004727void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4728 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004729{
Andre Guedes3655bba2013-10-30 19:01:40 -03004730 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
4731 struct mgmt_cp_disconnect *cp;
Johan Hedberg88c3df12012-02-09 14:27:38 +02004732 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004733 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004734
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004735 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4736 hdev);
4737
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004738 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004739 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004740 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004741
Andre Guedes3655bba2013-10-30 19:01:40 -03004742 cp = cmd->param;
4743
4744 if (bacmp(bdaddr, &cp->addr.bdaddr))
4745 return;
4746
4747 if (cp->addr.type != bdaddr_type)
4748 return;
4749
Johan Hedberg88c3df12012-02-09 14:27:38 +02004750 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes3655bba2013-10-30 19:01:40 -03004751 rp.addr.type = bdaddr_type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004752
Marcel Holtmann78929242013-10-06 23:55:47 -07004753 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4754 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004755
Johan Hedberga664b5b2011-02-19 12:06:02 -03004756 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004757}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004758
Marcel Holtmann445608d2013-10-06 23:55:48 -07004759void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4760 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004761{
4762 struct mgmt_ev_connect_failed ev;
4763
Johan Hedberg4c659c32011-11-07 23:13:39 +02004764 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004765 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004766 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004767
Marcel Holtmann445608d2013-10-06 23:55:48 -07004768 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004769}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004770
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004771void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004772{
4773 struct mgmt_ev_pin_code_request ev;
4774
Johan Hedbergd8457692012-02-17 14:24:57 +02004775 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004776 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004777 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004778
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004779 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004780}
4781
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004782void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4783 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004784{
4785 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004786 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004787
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004788 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004789 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004790 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004791
Johan Hedbergd8457692012-02-17 14:24:57 +02004792 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004793 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004794
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004795 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
4796 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004797
Johan Hedberga664b5b2011-02-19 12:06:02 -03004798 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004799}
4800
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004801void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4802 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004803{
4804 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004805 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004806
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004807 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004808 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004809 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004810
Johan Hedbergd8457692012-02-17 14:24:57 +02004811 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004812 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004813
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004814 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
4815 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004816
Johan Hedberga664b5b2011-02-19 12:06:02 -03004817 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004818}
Johan Hedberga5c29682011-02-19 12:05:57 -03004819
Johan Hedberg744cf192011-11-08 20:40:14 +02004820int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004821 u8 link_type, u8 addr_type, __le32 value,
4822 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004823{
4824 struct mgmt_ev_user_confirm_request ev;
4825
Johan Hedberg744cf192011-11-08 20:40:14 +02004826 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004827
Johan Hedberg272d90d2012-02-09 15:26:12 +02004828 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004829 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004830 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004831 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004832
Johan Hedberg744cf192011-11-08 20:40:14 +02004833 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004834 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004835}
4836
Johan Hedberg272d90d2012-02-09 15:26:12 +02004837int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004838 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004839{
4840 struct mgmt_ev_user_passkey_request ev;
4841
4842 BT_DBG("%s", hdev->name);
4843
Johan Hedberg272d90d2012-02-09 15:26:12 +02004844 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004845 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004846
4847 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004848 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004849}
4850
Brian Gix0df4c182011-11-16 13:53:13 -08004851static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004852 u8 link_type, u8 addr_type, u8 status,
4853 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004854{
4855 struct pending_cmd *cmd;
4856 struct mgmt_rp_user_confirm_reply rp;
4857 int err;
4858
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004859 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004860 if (!cmd)
4861 return -ENOENT;
4862
Johan Hedberg272d90d2012-02-09 15:26:12 +02004863 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004864 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004865 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004866 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004867
Johan Hedberga664b5b2011-02-19 12:06:02 -03004868 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004869
4870 return err;
4871}
4872
Johan Hedberg744cf192011-11-08 20:40:14 +02004873int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004874 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004875{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004876 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004877 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004878}
4879
Johan Hedberg272d90d2012-02-09 15:26:12 +02004880int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004881 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004882{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004883 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004884 status,
4885 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004886}
Johan Hedberg2a611692011-02-19 12:06:00 -03004887
Brian Gix604086b2011-11-23 08:28:33 -08004888int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004889 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004890{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004891 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004892 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004893}
4894
Johan Hedberg272d90d2012-02-09 15:26:12 +02004895int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004896 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004897{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004898 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004899 status,
4900 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004901}
4902
Johan Hedberg92a25252012-09-06 18:39:26 +03004903int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4904 u8 link_type, u8 addr_type, u32 passkey,
4905 u8 entered)
4906{
4907 struct mgmt_ev_passkey_notify ev;
4908
4909 BT_DBG("%s", hdev->name);
4910
4911 bacpy(&ev.addr.bdaddr, bdaddr);
4912 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4913 ev.passkey = __cpu_to_le32(passkey);
4914 ev.entered = entered;
4915
4916 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4917}
4918
Marcel Holtmanne5460992013-10-15 14:26:23 -07004919void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4920 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004921{
4922 struct mgmt_ev_auth_failed ev;
4923
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004924 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004925 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004926 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004927
Marcel Holtmanne5460992013-10-15 14:26:23 -07004928 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004929}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004930
Marcel Holtmann464996a2013-10-15 14:26:24 -07004931void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004932{
4933 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07004934 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004935
4936 if (status) {
4937 u8 mgmt_err = mgmt_status(status);
4938 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004939 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07004940 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004941 }
4942
Marcel Holtmann464996a2013-10-15 14:26:24 -07004943 if (test_bit(HCI_AUTH, &hdev->flags))
4944 changed = !test_and_set_bit(HCI_LINK_SECURITY,
4945 &hdev->dev_flags);
4946 else
4947 changed = test_and_clear_bit(HCI_LINK_SECURITY,
4948 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02004949
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004950 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004951 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004952
Johan Hedberg47990ea2012-02-22 11:58:37 +02004953 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07004954 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004955
4956 if (match.sk)
4957 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004958}
4959
Johan Hedberg890ea892013-03-15 17:06:52 -05004960static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004961{
Johan Hedberg890ea892013-03-15 17:06:52 -05004962 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004963 struct hci_cp_write_eir cp;
4964
Johan Hedberg976eb202012-10-24 21:12:01 +03004965 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004966 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004967
Johan Hedbergc80da272012-02-22 15:38:48 +02004968 memset(hdev->eir, 0, sizeof(hdev->eir));
4969
Johan Hedbergcacaf522012-02-21 00:52:42 +02004970 memset(&cp, 0, sizeof(cp));
4971
Johan Hedberg890ea892013-03-15 17:06:52 -05004972 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004973}
4974
Marcel Holtmann3e248562013-10-15 14:26:25 -07004975void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004976{
4977 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004978 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004979 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004980
4981 if (status) {
4982 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004983
4984 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004985 &hdev->dev_flags)) {
4986 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004987 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004988 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004989
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004990 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4991 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004992 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004993 }
4994
4995 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004996 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004997 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004998 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4999 if (!changed)
5000 changed = test_and_clear_bit(HCI_HS_ENABLED,
5001 &hdev->dev_flags);
5002 else
5003 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005004 }
5005
5006 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
5007
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005008 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07005009 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005010
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005011 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005012 sock_put(match.sk);
5013
Johan Hedberg890ea892013-03-15 17:06:52 -05005014 hci_req_init(&req, hdev);
5015
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005016 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05005017 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005018 else
Johan Hedberg890ea892013-03-15 17:06:52 -05005019 clear_eir(&req);
5020
5021 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005022}
5023
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005024void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
5025{
5026 struct cmd_lookup match = { NULL, hdev };
5027 bool changed = false;
5028
5029 if (status) {
5030 u8 mgmt_err = mgmt_status(status);
5031
5032 if (enable && test_and_clear_bit(HCI_SC_ENABLED,
5033 &hdev->dev_flags))
5034 new_settings(hdev, NULL);
5035
5036 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5037 cmd_status_rsp, &mgmt_err);
5038 return;
5039 }
5040
5041 if (enable)
5042 changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
5043 else
5044 changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
5045
5046 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5047 settings_rsp, &match);
5048
5049 if (changed)
5050 new_settings(hdev, match.sk);
5051
5052 if (match.sk)
5053 sock_put(match.sk);
5054}
5055
Johan Hedberg92da6092013-03-15 17:06:55 -05005056static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02005057{
5058 struct cmd_lookup *match = data;
5059
Johan Hedberg90e70452012-02-23 23:09:40 +02005060 if (match->sk == NULL) {
5061 match->sk = cmd->sk;
5062 sock_hold(match->sk);
5063 }
Johan Hedberg90e70452012-02-23 23:09:40 +02005064}
5065
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005066void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
5067 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005068{
Johan Hedberg90e70452012-02-23 23:09:40 +02005069 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005070
Johan Hedberg92da6092013-03-15 17:06:55 -05005071 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
5072 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
5073 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02005074
5075 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005076 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
5077 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02005078
5079 if (match.sk)
5080 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005081}
5082
Marcel Holtmann7667da32013-10-15 14:26:27 -07005083void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02005084{
Johan Hedbergb312b1612011-03-16 14:29:37 +02005085 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05005086 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005087
Johan Hedberg13928972013-03-15 17:07:00 -05005088 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07005089 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005090
5091 memset(&ev, 0, sizeof(ev));
5092 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005093 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005094
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005095 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05005096 if (!cmd) {
5097 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02005098
Johan Hedberg13928972013-03-15 17:07:00 -05005099 /* If this is a HCI command related to powering on the
5100 * HCI dev don't send any mgmt signals.
5101 */
5102 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07005103 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005104 }
5105
Marcel Holtmann7667da32013-10-15 14:26:27 -07005106 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
5107 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005108}
Szymon Jancc35938b2011-03-22 13:12:21 +01005109
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005110void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
5111 u8 *randomizer192, u8 *hash256,
5112 u8 *randomizer256, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01005113{
5114 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01005115
Johan Hedberg744cf192011-11-08 20:40:14 +02005116 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01005117
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005118 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01005119 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005120 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01005121
5122 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005123 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
5124 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01005125 } else {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005126 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
5127 hash256 && randomizer256) {
5128 struct mgmt_rp_read_local_oob_ext_data rp;
Szymon Jancc35938b2011-03-22 13:12:21 +01005129
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005130 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
5131 memcpy(rp.randomizer192, randomizer192,
5132 sizeof(rp.randomizer192));
Szymon Jancc35938b2011-03-22 13:12:21 +01005133
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005134 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
5135 memcpy(rp.randomizer256, randomizer256,
5136 sizeof(rp.randomizer256));
5137
5138 cmd_complete(cmd->sk, hdev->id,
5139 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5140 &rp, sizeof(rp));
5141 } else {
5142 struct mgmt_rp_read_local_oob_data rp;
5143
5144 memcpy(rp.hash, hash192, sizeof(rp.hash));
5145 memcpy(rp.randomizer, randomizer192,
5146 sizeof(rp.randomizer));
5147
5148 cmd_complete(cmd->sk, hdev->id,
5149 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5150 &rp, sizeof(rp));
5151 }
Szymon Jancc35938b2011-03-22 13:12:21 +01005152 }
5153
5154 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01005155}
Johan Hedberge17acd42011-03-30 23:57:16 +03005156
Marcel Holtmann901801b2013-10-06 23:55:51 -07005157void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5158 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
5159 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03005160{
Johan Hedberge319d2e2012-01-15 19:51:59 +02005161 char buf[512];
5162 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02005163 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03005164
Andre Guedes12602d02013-04-30 15:29:40 -03005165 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005166 return;
Andre Guedes12602d02013-04-30 15:29:40 -03005167
Johan Hedberg1dc06092012-01-15 21:01:23 +02005168 /* Leave 5 bytes for a potential CoD field */
5169 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005170 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03005171
Johan Hedberg1dc06092012-01-15 21:01:23 +02005172 memset(buf, 0, sizeof(buf));
5173
Johan Hedberge319d2e2012-01-15 19:51:59 +02005174 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005175 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02005176 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02005177 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305178 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02005179 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305180 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03005181
Johan Hedberg1dc06092012-01-15 21:01:23 +02005182 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02005183 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03005184
Johan Hedberg1dc06092012-01-15 21:01:23 +02005185 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
5186 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005187 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005188
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005189 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005190 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03005191
Marcel Holtmann901801b2013-10-06 23:55:51 -07005192 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03005193}
Johan Hedberga88a9652011-03-30 13:18:12 +03005194
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005195void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5196 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03005197{
Johan Hedbergb644ba32012-01-17 21:48:47 +02005198 struct mgmt_ev_device_found *ev;
5199 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
5200 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03005201
Johan Hedbergb644ba32012-01-17 21:48:47 +02005202 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03005203
Johan Hedbergb644ba32012-01-17 21:48:47 +02005204 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03005205
Johan Hedbergb644ba32012-01-17 21:48:47 +02005206 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005207 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005208 ev->rssi = rssi;
5209
5210 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005211 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005212
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005213 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005214
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005215 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03005216}
Johan Hedberg314b2382011-04-27 10:29:57 -04005217
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005218void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04005219{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005220 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02005221 struct pending_cmd *cmd;
5222
Andre Guedes343fb142011-11-22 17:14:19 -03005223 BT_DBG("%s discovering %u", hdev->name, discovering);
5224
Johan Hedberg164a6e72011-11-01 17:06:44 +02005225 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005226 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005227 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005228 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005229
5230 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02005231 u8 type = hdev->discovery.type;
5232
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005233 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
5234 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02005235 mgmt_pending_remove(cmd);
5236 }
5237
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005238 memset(&ev, 0, sizeof(ev));
5239 ev.type = hdev->discovery.type;
5240 ev.discovering = discovering;
5241
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005242 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04005243}
Antti Julku5e762442011-08-25 16:48:02 +03005244
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005245int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005246{
5247 struct pending_cmd *cmd;
5248 struct mgmt_ev_device_blocked ev;
5249
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005250 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005251
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005252 bacpy(&ev.addr.bdaddr, bdaddr);
5253 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005254
Johan Hedberg744cf192011-11-08 20:40:14 +02005255 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005256 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005257}
5258
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005259int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005260{
5261 struct pending_cmd *cmd;
5262 struct mgmt_ev_device_unblocked ev;
5263
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005264 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005265
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005266 bacpy(&ev.addr.bdaddr, bdaddr);
5267 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005268
Johan Hedberg744cf192011-11-08 20:40:14 +02005269 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005270 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005271}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005272
5273static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5274{
5275 BT_DBG("%s status %u", hdev->name, status);
5276
5277 /* Clear the advertising mgmt setting if we failed to re-enable it */
5278 if (status) {
5279 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005280 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005281 }
5282}
5283
5284void mgmt_reenable_advertising(struct hci_dev *hdev)
5285{
5286 struct hci_request req;
5287
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005288 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005289 return;
5290
5291 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5292 return;
5293
5294 hci_req_init(&req, hdev);
5295 enable_advertising(&req);
5296
5297 /* If this fails we have no option but to let user space know
5298 * that we've disabled advertising.
5299 */
5300 if (hci_req_run(&req, adv_enable_complete) < 0) {
5301 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005302 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005303 }
5304}