blob: a7d4ae679ab76407525040349251f88ff78203ba [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070033
34#include "smp.h"
Johan Hedberg03811012010-12-08 00:21:06 +020035
Johan Hedberg2da9c552012-02-17 14:39:28 +020036#define MGMT_VERSION 1
Marcel Holtmann9ab8cf32013-10-02 05:18:31 -070037#define MGMT_REVISION 4
Johan Hedberg02d98122010-12-13 21:07:04 +020038
Johan Hedberge70bb2e2012-02-13 16:59:33 +020039static const u16 mgmt_commands[] = {
40 MGMT_OP_READ_INDEX_LIST,
41 MGMT_OP_READ_INFO,
42 MGMT_OP_SET_POWERED,
43 MGMT_OP_SET_DISCOVERABLE,
44 MGMT_OP_SET_CONNECTABLE,
45 MGMT_OP_SET_FAST_CONNECTABLE,
46 MGMT_OP_SET_PAIRABLE,
47 MGMT_OP_SET_LINK_SECURITY,
48 MGMT_OP_SET_SSP,
49 MGMT_OP_SET_HS,
50 MGMT_OP_SET_LE,
51 MGMT_OP_SET_DEV_CLASS,
52 MGMT_OP_SET_LOCAL_NAME,
53 MGMT_OP_ADD_UUID,
54 MGMT_OP_REMOVE_UUID,
55 MGMT_OP_LOAD_LINK_KEYS,
56 MGMT_OP_LOAD_LONG_TERM_KEYS,
57 MGMT_OP_DISCONNECT,
58 MGMT_OP_GET_CONNECTIONS,
59 MGMT_OP_PIN_CODE_REPLY,
60 MGMT_OP_PIN_CODE_NEG_REPLY,
61 MGMT_OP_SET_IO_CAPABILITY,
62 MGMT_OP_PAIR_DEVICE,
63 MGMT_OP_CANCEL_PAIR_DEVICE,
64 MGMT_OP_UNPAIR_DEVICE,
65 MGMT_OP_USER_CONFIRM_REPLY,
66 MGMT_OP_USER_CONFIRM_NEG_REPLY,
67 MGMT_OP_USER_PASSKEY_REPLY,
68 MGMT_OP_USER_PASSKEY_NEG_REPLY,
69 MGMT_OP_READ_LOCAL_OOB_DATA,
70 MGMT_OP_ADD_REMOTE_OOB_DATA,
71 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
72 MGMT_OP_START_DISCOVERY,
73 MGMT_OP_STOP_DISCOVERY,
74 MGMT_OP_CONFIRM_NAME,
75 MGMT_OP_BLOCK_DEVICE,
76 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070077 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030078 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030079 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070080 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070081 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080082 MGMT_OP_SET_SECURE_CONN,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020083};
84
85static const u16 mgmt_events[] = {
86 MGMT_EV_CONTROLLER_ERROR,
87 MGMT_EV_INDEX_ADDED,
88 MGMT_EV_INDEX_REMOVED,
89 MGMT_EV_NEW_SETTINGS,
90 MGMT_EV_CLASS_OF_DEV_CHANGED,
91 MGMT_EV_LOCAL_NAME_CHANGED,
92 MGMT_EV_NEW_LINK_KEY,
93 MGMT_EV_NEW_LONG_TERM_KEY,
94 MGMT_EV_DEVICE_CONNECTED,
95 MGMT_EV_DEVICE_DISCONNECTED,
96 MGMT_EV_CONNECT_FAILED,
97 MGMT_EV_PIN_CODE_REQUEST,
98 MGMT_EV_USER_CONFIRM_REQUEST,
99 MGMT_EV_USER_PASSKEY_REQUEST,
100 MGMT_EV_AUTH_FAILED,
101 MGMT_EV_DEVICE_FOUND,
102 MGMT_EV_DISCOVERING,
103 MGMT_EV_DEVICE_BLOCKED,
104 MGMT_EV_DEVICE_UNBLOCKED,
105 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300106 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200107};
108
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800109#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200110
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200111#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
112 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
113
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200114struct pending_cmd {
115 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200116 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200117 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100118 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200119 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300120 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200121};
122
Johan Hedbergca69b792011-11-11 18:10:00 +0200123/* HCI to MGMT error code conversion table */
124static u8 mgmt_status_table[] = {
125 MGMT_STATUS_SUCCESS,
126 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
127 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
128 MGMT_STATUS_FAILED, /* Hardware Failure */
129 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
130 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
131 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
132 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
133 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
134 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
135 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
136 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
137 MGMT_STATUS_BUSY, /* Command Disallowed */
138 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
139 MGMT_STATUS_REJECTED, /* Rejected Security */
140 MGMT_STATUS_REJECTED, /* Rejected Personal */
141 MGMT_STATUS_TIMEOUT, /* Host Timeout */
142 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
143 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
144 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
145 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
146 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
147 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
148 MGMT_STATUS_BUSY, /* Repeated Attempts */
149 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
150 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
151 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
152 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
153 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
154 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
155 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
156 MGMT_STATUS_FAILED, /* Unspecified Error */
157 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
158 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
159 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
160 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
161 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
162 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
163 MGMT_STATUS_FAILED, /* Unit Link Key Used */
164 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
165 MGMT_STATUS_TIMEOUT, /* Instant Passed */
166 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
167 MGMT_STATUS_FAILED, /* Transaction Collision */
168 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
169 MGMT_STATUS_REJECTED, /* QoS Rejected */
170 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
171 MGMT_STATUS_REJECTED, /* Insufficient Security */
172 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
173 MGMT_STATUS_BUSY, /* Role Switch Pending */
174 MGMT_STATUS_FAILED, /* Slot Violation */
175 MGMT_STATUS_FAILED, /* Role Switch Failed */
176 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
177 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
178 MGMT_STATUS_BUSY, /* Host Busy Pairing */
179 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
180 MGMT_STATUS_BUSY, /* Controller Busy */
181 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
182 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
183 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
184 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
185 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
186};
187
188static u8 mgmt_status(u8 hci_status)
189{
190 if (hci_status < ARRAY_SIZE(mgmt_status_table))
191 return mgmt_status_table[hci_status];
192
193 return MGMT_STATUS_FAILED;
194}
195
Szymon Janc4e51eae2011-02-25 19:05:48 +0100196static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan 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
381 if (lmp_sc_capable(hdev))
382 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700383 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100384
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300385 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200386 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300387 settings |= MGMT_SETTING_ADVERTISING;
388 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200389
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200390 return settings;
391}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200392
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200393static u32 get_current_settings(struct hci_dev *hdev)
394{
395 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200396
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200397 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100398 settings |= MGMT_SETTING_POWERED;
399
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200400 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200401 settings |= MGMT_SETTING_CONNECTABLE;
402
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500403 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
404 settings |= MGMT_SETTING_FAST_CONNECTABLE;
405
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200406 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200407 settings |= MGMT_SETTING_DISCOVERABLE;
408
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200409 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200410 settings |= MGMT_SETTING_PAIRABLE;
411
Johan Hedberg56f87902013-10-02 13:43:13 +0300412 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200413 settings |= MGMT_SETTING_BREDR;
414
Johan Hedberg06199cf2012-02-22 16:37:11 +0200415 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200416 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200417
Johan Hedberg47990ea2012-02-22 11:58:37 +0200418 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200419 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200420
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200421 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200423
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200424 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
425 settings |= MGMT_SETTING_HS;
426
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200427 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300428 settings |= MGMT_SETTING_ADVERTISING;
429
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800430 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
431 settings |= MGMT_SETTING_SECURE_CONN;
432
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200433 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200434}
435
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300436#define PNP_INFO_SVCLASS_ID 0x1200
437
Johan Hedberg213202e2013-01-27 00:31:33 +0200438static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
439{
440 u8 *ptr = data, *uuids_start = NULL;
441 struct bt_uuid *uuid;
442
443 if (len < 4)
444 return ptr;
445
446 list_for_each_entry(uuid, &hdev->uuids, list) {
447 u16 uuid16;
448
449 if (uuid->size != 16)
450 continue;
451
452 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
453 if (uuid16 < 0x1100)
454 continue;
455
456 if (uuid16 == PNP_INFO_SVCLASS_ID)
457 continue;
458
459 if (!uuids_start) {
460 uuids_start = ptr;
461 uuids_start[0] = 1;
462 uuids_start[1] = EIR_UUID16_ALL;
463 ptr += 2;
464 }
465
466 /* Stop if not enough space to put next UUID */
467 if ((ptr - data) + sizeof(u16) > len) {
468 uuids_start[1] = EIR_UUID16_SOME;
469 break;
470 }
471
472 *ptr++ = (uuid16 & 0x00ff);
473 *ptr++ = (uuid16 & 0xff00) >> 8;
474 uuids_start[0] += sizeof(uuid16);
475 }
476
477 return ptr;
478}
479
Johan Hedbergcdf19632013-01-27 00:31:34 +0200480static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
481{
482 u8 *ptr = data, *uuids_start = NULL;
483 struct bt_uuid *uuid;
484
485 if (len < 6)
486 return ptr;
487
488 list_for_each_entry(uuid, &hdev->uuids, list) {
489 if (uuid->size != 32)
490 continue;
491
492 if (!uuids_start) {
493 uuids_start = ptr;
494 uuids_start[0] = 1;
495 uuids_start[1] = EIR_UUID32_ALL;
496 ptr += 2;
497 }
498
499 /* Stop if not enough space to put next UUID */
500 if ((ptr - data) + sizeof(u32) > len) {
501 uuids_start[1] = EIR_UUID32_SOME;
502 break;
503 }
504
505 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
506 ptr += sizeof(u32);
507 uuids_start[0] += sizeof(u32);
508 }
509
510 return ptr;
511}
512
Johan Hedbergc00d5752013-01-27 00:31:35 +0200513static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
514{
515 u8 *ptr = data, *uuids_start = NULL;
516 struct bt_uuid *uuid;
517
518 if (len < 18)
519 return ptr;
520
521 list_for_each_entry(uuid, &hdev->uuids, list) {
522 if (uuid->size != 128)
523 continue;
524
525 if (!uuids_start) {
526 uuids_start = ptr;
527 uuids_start[0] = 1;
528 uuids_start[1] = EIR_UUID128_ALL;
529 ptr += 2;
530 }
531
532 /* Stop if not enough space to put next UUID */
533 if ((ptr - data) + 16 > len) {
534 uuids_start[1] = EIR_UUID128_SOME;
535 break;
536 }
537
538 memcpy(ptr, uuid->uuid, 16);
539 ptr += 16;
540 uuids_start[0] += 16;
541 }
542
543 return ptr;
544}
545
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300546static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
547{
548 struct pending_cmd *cmd;
549
550 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
551 if (cmd->opcode == opcode)
552 return cmd;
553 }
554
555 return NULL;
556}
557
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700558static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
559{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700560 u8 ad_len = 0;
561 size_t name_len;
562
563 name_len = strlen(hdev->dev_name);
564 if (name_len > 0) {
565 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
566
567 if (name_len > max_len) {
568 name_len = max_len;
569 ptr[1] = EIR_NAME_SHORT;
570 } else
571 ptr[1] = EIR_NAME_COMPLETE;
572
573 ptr[0] = name_len + 1;
574
575 memcpy(ptr + 2, hdev->dev_name, name_len);
576
577 ad_len += (name_len + 2);
578 ptr += (name_len + 2);
579 }
580
581 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700582}
583
584static void update_scan_rsp_data(struct hci_request *req)
585{
586 struct hci_dev *hdev = req->hdev;
587 struct hci_cp_le_set_scan_rsp_data cp;
588 u8 len;
589
Johan Hedberg7751ef12013-10-19 23:38:15 +0300590 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700591 return;
592
593 memset(&cp, 0, sizeof(cp));
594
595 len = create_scan_rsp_data(hdev, cp.data);
596
Johan Hedbergeb438b52013-10-16 15:31:07 +0300597 if (hdev->scan_rsp_data_len == len &&
598 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700599 return;
600
Johan Hedbergeb438b52013-10-16 15:31:07 +0300601 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
602 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700603
604 cp.length = len;
605
606 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
607}
608
Johan Hedberg9a43e252013-10-20 19:00:07 +0300609static u8 get_adv_discov_flags(struct hci_dev *hdev)
610{
611 struct pending_cmd *cmd;
612
613 /* If there's a pending mgmt command the flags will not yet have
614 * their final values, so check for this first.
615 */
616 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
617 if (cmd) {
618 struct mgmt_mode *cp = cmd->param;
619 if (cp->val == 0x01)
620 return LE_AD_GENERAL;
621 else if (cp->val == 0x02)
622 return LE_AD_LIMITED;
623 } else {
624 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
625 return LE_AD_LIMITED;
626 else if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
627 return LE_AD_GENERAL;
628 }
629
630 return 0;
631}
632
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700633static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700634{
635 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700636
Johan Hedberg9a43e252013-10-20 19:00:07 +0300637 flags |= get_adv_discov_flags(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700638
639 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
640 if (lmp_le_br_capable(hdev))
641 flags |= LE_AD_SIM_LE_BREDR_CTRL;
642 if (lmp_host_le_br_capable(hdev))
643 flags |= LE_AD_SIM_LE_BREDR_HOST;
644 } else {
645 flags |= LE_AD_NO_BREDR;
646 }
647
648 if (flags) {
649 BT_DBG("adv flags 0x%02x", flags);
650
651 ptr[0] = 2;
652 ptr[1] = EIR_FLAGS;
653 ptr[2] = flags;
654
655 ad_len += 3;
656 ptr += 3;
657 }
658
659 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
660 ptr[0] = 2;
661 ptr[1] = EIR_TX_POWER;
662 ptr[2] = (u8) hdev->adv_tx_power;
663
664 ad_len += 3;
665 ptr += 3;
666 }
667
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700668 return ad_len;
669}
670
Marcel Holtmann5947f4b2013-10-16 00:16:50 -0700671static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700672{
673 struct hci_dev *hdev = req->hdev;
674 struct hci_cp_le_set_adv_data cp;
675 u8 len;
676
Johan Hedberg10994ce2013-10-19 23:38:16 +0300677 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700678 return;
679
680 memset(&cp, 0, sizeof(cp));
681
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700682 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700683
684 if (hdev->adv_data_len == len &&
685 memcmp(cp.data, hdev->adv_data, len) == 0)
686 return;
687
688 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
689 hdev->adv_data_len = len;
690
691 cp.length = len;
692
693 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
694}
695
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300696static void create_eir(struct hci_dev *hdev, u8 *data)
697{
698 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300699 size_t name_len;
700
701 name_len = strlen(hdev->dev_name);
702
703 if (name_len > 0) {
704 /* EIR Data type */
705 if (name_len > 48) {
706 name_len = 48;
707 ptr[1] = EIR_NAME_SHORT;
708 } else
709 ptr[1] = EIR_NAME_COMPLETE;
710
711 /* EIR Data length */
712 ptr[0] = name_len + 1;
713
714 memcpy(ptr + 2, hdev->dev_name, name_len);
715
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300716 ptr += (name_len + 2);
717 }
718
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100719 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700720 ptr[0] = 2;
721 ptr[1] = EIR_TX_POWER;
722 ptr[2] = (u8) hdev->inq_tx_power;
723
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700724 ptr += 3;
725 }
726
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700727 if (hdev->devid_source > 0) {
728 ptr[0] = 9;
729 ptr[1] = EIR_DEVICE_ID;
730
731 put_unaligned_le16(hdev->devid_source, ptr + 2);
732 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
733 put_unaligned_le16(hdev->devid_product, ptr + 6);
734 put_unaligned_le16(hdev->devid_version, ptr + 8);
735
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700736 ptr += 10;
737 }
738
Johan Hedberg213202e2013-01-27 00:31:33 +0200739 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200740 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200741 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300742}
743
Johan Hedberg890ea892013-03-15 17:06:52 -0500744static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300745{
Johan Hedberg890ea892013-03-15 17:06:52 -0500746 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300747 struct hci_cp_write_eir cp;
748
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200749 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500750 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200751
Johan Hedberg976eb202012-10-24 21:12:01 +0300752 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500753 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300754
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200755 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500756 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300757
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200758 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500759 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300760
761 memset(&cp, 0, sizeof(cp));
762
763 create_eir(hdev, cp.data);
764
765 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500766 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300767
768 memcpy(hdev->eir, cp.data, sizeof(cp.data));
769
Johan Hedberg890ea892013-03-15 17:06:52 -0500770 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300771}
772
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200773static u8 get_service_classes(struct hci_dev *hdev)
774{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300775 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200776 u8 val = 0;
777
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300778 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200779 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200780
781 return val;
782}
783
Johan Hedberg890ea892013-03-15 17:06:52 -0500784static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200785{
Johan Hedberg890ea892013-03-15 17:06:52 -0500786 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200787 u8 cod[3];
788
789 BT_DBG("%s", hdev->name);
790
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200791 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500792 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200793
Johan Hedbergf87ea1d2013-10-19 23:38:17 +0300794 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
795 return;
796
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200797 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500798 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200799
800 cod[0] = hdev->minor_class;
801 cod[1] = hdev->major_class;
802 cod[2] = get_service_classes(hdev);
803
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700804 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
805 cod[1] |= 0x20;
806
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200807 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500808 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200809
Johan Hedberg890ea892013-03-15 17:06:52 -0500810 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200811}
812
Johan Hedberg7d785252011-12-15 00:47:39 +0200813static void service_cache_off(struct work_struct *work)
814{
815 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300816 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500817 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200818
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200819 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200820 return;
821
Johan Hedberg890ea892013-03-15 17:06:52 -0500822 hci_req_init(&req, hdev);
823
Johan Hedberg7d785252011-12-15 00:47:39 +0200824 hci_dev_lock(hdev);
825
Johan Hedberg890ea892013-03-15 17:06:52 -0500826 update_eir(&req);
827 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200828
829 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500830
831 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200832}
833
Johan Hedberg6a919082012-02-28 06:17:26 +0200834static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200835{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200836 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200837 return;
838
Johan Hedberg4f87da82012-03-02 19:55:56 +0200839 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200840
Johan Hedberg4f87da82012-03-02 19:55:56 +0200841 /* Non-mgmt controlled devices get this bit set
842 * implicitly so that pairing works for them, however
843 * for mgmt we require user-space to explicitly enable
844 * it
845 */
846 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200847}
848
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200849static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300850 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200851{
852 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200853
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200854 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200855
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300856 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200857
Johan Hedberg03811012010-12-08 00:21:06 +0200858 memset(&rp, 0, sizeof(rp));
859
Johan Hedberg03811012010-12-08 00:21:06 +0200860 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200861
862 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200863 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200864
865 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
866 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
867
868 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200869
870 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200871 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200872
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300873 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200874
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200875 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300876 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200877}
878
879static void mgmt_pending_free(struct pending_cmd *cmd)
880{
881 sock_put(cmd->sk);
882 kfree(cmd->param);
883 kfree(cmd);
884}
885
886static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300887 struct hci_dev *hdev, void *data,
888 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200889{
890 struct pending_cmd *cmd;
891
Andre Guedes12b94562012-06-07 19:05:45 -0300892 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200893 if (!cmd)
894 return NULL;
895
896 cmd->opcode = opcode;
897 cmd->index = hdev->id;
898
Andre Guedes12b94562012-06-07 19:05:45 -0300899 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200900 if (!cmd->param) {
901 kfree(cmd);
902 return NULL;
903 }
904
905 if (data)
906 memcpy(cmd->param, data, len);
907
908 cmd->sk = sk;
909 sock_hold(sk);
910
911 list_add(&cmd->list, &hdev->mgmt_pending);
912
913 return cmd;
914}
915
916static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300917 void (*cb)(struct pending_cmd *cmd,
918 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300919 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200920{
Andre Guedesa3d09352013-02-01 11:21:30 -0300921 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200922
Andre Guedesa3d09352013-02-01 11:21:30 -0300923 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200924 if (opcode > 0 && cmd->opcode != opcode)
925 continue;
926
927 cb(cmd, data);
928 }
929}
930
Johan Hedberg03811012010-12-08 00:21:06 +0200931static void mgmt_pending_remove(struct pending_cmd *cmd)
932{
933 list_del(&cmd->list);
934 mgmt_pending_free(cmd);
935}
936
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200937static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200938{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200939 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200940
Johan Hedbergaee9b212012-02-18 15:07:59 +0200941 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300942 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200943}
944
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200945static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300946 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200947{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300948 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200949 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200950 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200951
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200952 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200953
Johan Hedberga7e80f22013-01-09 16:05:19 +0200954 if (cp->val != 0x00 && cp->val != 0x01)
955 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
956 MGMT_STATUS_INVALID_PARAMS);
957
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300958 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200959
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300960 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
961 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
962 MGMT_STATUS_BUSY);
963 goto failed;
964 }
965
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100966 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
967 cancel_delayed_work(&hdev->power_off);
968
969 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200970 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
971 data, len);
972 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100973 goto failed;
974 }
975 }
976
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200977 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200978 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200979 goto failed;
980 }
981
Johan Hedberg03811012010-12-08 00:21:06 +0200982 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
983 if (!cmd) {
984 err = -ENOMEM;
985 goto failed;
986 }
987
988 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200989 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200990 else
Johan Hedberg19202572013-01-14 22:33:51 +0200991 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200992
993 err = 0;
994
995failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300996 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200997 return err;
998}
999
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001000static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
1001 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001002{
1003 struct sk_buff *skb;
1004 struct mgmt_hdr *hdr;
1005
Andre Guedes790eff42012-06-07 19:05:46 -03001006 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001007 if (!skb)
1008 return -ENOMEM;
1009
1010 hdr = (void *) skb_put(skb, sizeof(*hdr));
1011 hdr->opcode = cpu_to_le16(event);
1012 if (hdev)
1013 hdr->index = cpu_to_le16(hdev->id);
1014 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05301015 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001016 hdr->len = cpu_to_le16(data_len);
1017
1018 if (data)
1019 memcpy(skb_put(skb, data_len), data, data_len);
1020
Marcel Holtmann97e0bde2012-02-22 13:49:28 +01001021 /* Time stamp */
1022 __net_timestamp(skb);
1023
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001024 hci_send_to_control(skb, skip_sk);
1025 kfree_skb(skb);
1026
1027 return 0;
1028}
1029
1030static int new_settings(struct hci_dev *hdev, struct sock *skip)
1031{
1032 __le32 ev;
1033
1034 ev = cpu_to_le32(get_current_settings(hdev));
1035
1036 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1037}
1038
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001039struct cmd_lookup {
1040 struct sock *sk;
1041 struct hci_dev *hdev;
1042 u8 mgmt_status;
1043};
1044
1045static void settings_rsp(struct pending_cmd *cmd, void *data)
1046{
1047 struct cmd_lookup *match = data;
1048
1049 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1050
1051 list_del(&cmd->list);
1052
1053 if (match->sk == NULL) {
1054 match->sk = cmd->sk;
1055 sock_hold(match->sk);
1056 }
1057
1058 mgmt_pending_free(cmd);
1059}
1060
1061static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1062{
1063 u8 *status = data;
1064
1065 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1066 mgmt_pending_remove(cmd);
1067}
1068
Johan Hedberge6fe7982013-10-02 15:45:22 +03001069static u8 mgmt_bredr_support(struct hci_dev *hdev)
1070{
1071 if (!lmp_bredr_capable(hdev))
1072 return MGMT_STATUS_NOT_SUPPORTED;
1073 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1074 return MGMT_STATUS_REJECTED;
1075 else
1076 return MGMT_STATUS_SUCCESS;
1077}
1078
1079static u8 mgmt_le_support(struct hci_dev *hdev)
1080{
1081 if (!lmp_le_capable(hdev))
1082 return MGMT_STATUS_NOT_SUPPORTED;
1083 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1084 return MGMT_STATUS_REJECTED;
1085 else
1086 return MGMT_STATUS_SUCCESS;
1087}
1088
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001089static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1090{
1091 struct pending_cmd *cmd;
1092 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001093 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001094 bool changed;
1095
1096 BT_DBG("status 0x%02x", status);
1097
1098 hci_dev_lock(hdev);
1099
1100 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1101 if (!cmd)
1102 goto unlock;
1103
1104 if (status) {
1105 u8 mgmt_err = mgmt_status(status);
1106 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001107 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001108 goto remove_cmd;
1109 }
1110
1111 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001112 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001113 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1114 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001115
1116 if (hdev->discov_timeout > 0) {
1117 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1118 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1119 to);
1120 }
1121 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001122 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1123 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001124 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001125
1126 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1127
1128 if (changed)
1129 new_settings(hdev, cmd->sk);
1130
Marcel Holtmann970ba522013-10-15 06:33:57 -07001131 /* When the discoverable mode gets changed, make sure
1132 * that class of device has the limited discoverable
1133 * bit correctly set.
1134 */
1135 hci_req_init(&req, hdev);
1136 update_class(&req);
1137 hci_req_run(&req, NULL);
1138
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001139remove_cmd:
1140 mgmt_pending_remove(cmd);
1141
1142unlock:
1143 hci_dev_unlock(hdev);
1144}
1145
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001146static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001147 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001148{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001149 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001150 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001151 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001152 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001153 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001154 int err;
1155
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001156 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001157
Johan Hedberg9a43e252013-10-20 19:00:07 +03001158 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1159 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001160 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberg9a43e252013-10-20 19:00:07 +03001161 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001162
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001163 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga7e80f22013-01-09 16:05:19 +02001164 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1165 MGMT_STATUS_INVALID_PARAMS);
1166
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001167 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001168
1169 /* Disabling discoverable requires that no timeout is set,
1170 * and enabling limited discoverable requires a timeout.
1171 */
1172 if ((cp->val == 0x00 && timeout > 0) ||
1173 (cp->val == 0x02 && timeout == 0))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001174 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001175 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001176
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001177 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001178
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001179 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001180 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001181 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001182 goto failed;
1183 }
1184
1185 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001186 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001187 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001188 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001189 goto failed;
1190 }
1191
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001192 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001193 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001194 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001195 goto failed;
1196 }
1197
1198 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001199 bool changed = false;
1200
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001201 /* Setting limited discoverable when powered off is
1202 * not a valid operation since it requires a timeout
1203 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1204 */
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001205 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1206 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1207 changed = true;
1208 }
1209
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001210 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001211 if (err < 0)
1212 goto failed;
1213
1214 if (changed)
1215 err = new_settings(hdev, sk);
1216
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001217 goto failed;
1218 }
1219
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001220 /* If the current mode is the same, then just update the timeout
1221 * value with the new value. And if only the timeout gets updated,
1222 * then no need for any HCI transactions.
1223 */
1224 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) &&
1225 (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE,
1226 &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001227 cancel_delayed_work(&hdev->discov_off);
1228 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001229
Marcel Holtmann36261542013-10-15 08:28:51 -07001230 if (cp->val && hdev->discov_timeout > 0) {
1231 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001232 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001233 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001234 }
1235
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001236 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001237 goto failed;
1238 }
1239
1240 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1241 if (!cmd) {
1242 err = -ENOMEM;
1243 goto failed;
1244 }
1245
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001246 /* Cancel any potential discoverable timeout that might be
1247 * still active and store new timeout value. The arming of
1248 * the timeout happens in the complete handler.
1249 */
1250 cancel_delayed_work(&hdev->discov_off);
1251 hdev->discov_timeout = timeout;
1252
Johan Hedbergb456f872013-10-19 23:38:22 +03001253 /* Limited discoverable mode */
1254 if (cp->val == 0x02)
1255 set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1256 else
1257 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1258
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001259 hci_req_init(&req, hdev);
1260
Johan Hedberg9a43e252013-10-20 19:00:07 +03001261 /* The procedure for LE-only controllers is much simpler - just
1262 * update the advertising data.
1263 */
1264 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1265 goto update_ad;
1266
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001267 scan = SCAN_PAGE;
1268
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001269 if (cp->val) {
1270 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001271
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001272 if (cp->val == 0x02) {
1273 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001274 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001275 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1276 hci_cp.iac_lap[1] = 0x8b;
1277 hci_cp.iac_lap[2] = 0x9e;
1278 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1279 hci_cp.iac_lap[4] = 0x8b;
1280 hci_cp.iac_lap[5] = 0x9e;
1281 } else {
1282 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001283 hci_cp.num_iac = 1;
1284 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1285 hci_cp.iac_lap[1] = 0x8b;
1286 hci_cp.iac_lap[2] = 0x9e;
1287 }
1288
1289 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1290 (hci_cp.num_iac * 3) + 1, &hci_cp);
1291
1292 scan |= SCAN_INQUIRY;
1293 } else {
1294 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1295 }
1296
1297 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001298
Johan Hedberg9a43e252013-10-20 19:00:07 +03001299update_ad:
1300 update_adv_data(&req);
1301
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001302 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001303 if (err < 0)
1304 mgmt_pending_remove(cmd);
1305
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001306failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001307 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001308 return err;
1309}
1310
Johan Hedberg406d7802013-03-15 17:07:09 -05001311static void write_fast_connectable(struct hci_request *req, bool enable)
1312{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001313 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001314 struct hci_cp_write_page_scan_activity acp;
1315 u8 type;
1316
Johan Hedberg547003b2013-10-21 16:51:53 +03001317 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1318 return;
1319
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001320 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1321 return;
1322
Johan Hedberg406d7802013-03-15 17:07:09 -05001323 if (enable) {
1324 type = PAGE_SCAN_TYPE_INTERLACED;
1325
1326 /* 160 msec page scan interval */
1327 acp.interval = __constant_cpu_to_le16(0x0100);
1328 } else {
1329 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1330
1331 /* default 1.28 sec page scan */
1332 acp.interval = __constant_cpu_to_le16(0x0800);
1333 }
1334
1335 acp.window = __constant_cpu_to_le16(0x0012);
1336
Johan Hedbergbd98b992013-03-15 17:07:13 -05001337 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1338 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1339 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1340 sizeof(acp), &acp);
1341
1342 if (hdev->page_scan_type != type)
1343 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001344}
1345
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001346static u8 get_adv_type(struct hci_dev *hdev)
1347{
1348 struct pending_cmd *cmd;
1349 bool connectable;
1350
1351 /* If there's a pending mgmt command the flag will not yet have
1352 * it's final value, so check for this first.
1353 */
1354 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1355 if (cmd) {
1356 struct mgmt_mode *cp = cmd->param;
1357 connectable = !!cp->val;
1358 } else {
1359 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1360 }
1361
1362 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1363}
1364
Johan Hedberg95c66e72013-10-14 16:20:06 +03001365static void enable_advertising(struct hci_request *req)
1366{
1367 struct hci_dev *hdev = req->hdev;
1368 struct hci_cp_le_set_adv_param cp;
1369 u8 enable = 0x01;
1370
1371 memset(&cp, 0, sizeof(cp));
1372 cp.min_interval = __constant_cpu_to_le16(0x0800);
1373 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001374 cp.type = get_adv_type(hdev);
Marcel Holtmann79830f62013-10-18 16:38:09 -07001375 cp.own_address_type = hdev->own_addr_type;
Johan Hedberg95c66e72013-10-14 16:20:06 +03001376 cp.channel_map = 0x07;
1377
1378 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1379
1380 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1381}
1382
1383static void disable_advertising(struct hci_request *req)
1384{
1385 u8 enable = 0x00;
1386
1387 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1388}
1389
Johan Hedberg2b76f452013-03-15 17:07:04 -05001390static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1391{
1392 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001393 struct mgmt_mode *cp;
1394 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001395
1396 BT_DBG("status 0x%02x", status);
1397
1398 hci_dev_lock(hdev);
1399
1400 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1401 if (!cmd)
1402 goto unlock;
1403
Johan Hedberg37438c12013-10-14 16:20:05 +03001404 if (status) {
1405 u8 mgmt_err = mgmt_status(status);
1406 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1407 goto remove_cmd;
1408 }
1409
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001410 cp = cmd->param;
1411 if (cp->val)
1412 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1413 else
1414 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1415
Johan Hedberg2b76f452013-03-15 17:07:04 -05001416 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1417
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001418 if (changed)
1419 new_settings(hdev, cmd->sk);
1420
Johan Hedberg37438c12013-10-14 16:20:05 +03001421remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001422 mgmt_pending_remove(cmd);
1423
1424unlock:
1425 hci_dev_unlock(hdev);
1426}
1427
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001428static int set_connectable_update_settings(struct hci_dev *hdev,
1429 struct sock *sk, u8 val)
1430{
1431 bool changed = false;
1432 int err;
1433
1434 if (!!val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1435 changed = true;
1436
1437 if (val) {
1438 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1439 } else {
1440 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1441 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1442 }
1443
1444 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1445 if (err < 0)
1446 return err;
1447
1448 if (changed)
1449 return new_settings(hdev, sk);
1450
1451 return 0;
1452}
1453
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001454static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001455 u16 len)
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001456{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001457 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001458 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001459 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001460 u8 scan;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001461 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001462
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001463 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001464
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001465 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1466 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001467 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001468 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001469
Johan Hedberga7e80f22013-01-09 16:05:19 +02001470 if (cp->val != 0x00 && cp->val != 0x01)
1471 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1472 MGMT_STATUS_INVALID_PARAMS);
1473
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001474 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001475
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001476 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001477 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001478 goto failed;
1479 }
1480
1481 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001482 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001483 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001484 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001485 goto failed;
1486 }
1487
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001488 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1489 if (!cmd) {
1490 err = -ENOMEM;
1491 goto failed;
1492 }
1493
Johan Hedberg2b76f452013-03-15 17:07:04 -05001494 hci_req_init(&req, hdev);
1495
Johan Hedberg9a43e252013-10-20 19:00:07 +03001496 /* If BR/EDR is not enabled and we disable advertising as a
1497 * by-product of disabling connectable, we need to update the
1498 * advertising flags.
1499 */
1500 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
1501 if (!cp->val) {
1502 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1503 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1504 }
1505 update_adv_data(&req);
1506 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001507 if (cp->val) {
1508 scan = SCAN_PAGE;
1509 } else {
1510 scan = 0;
1511
1512 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001513 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001514 cancel_delayed_work(&hdev->discov_off);
1515 }
1516
1517 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1518 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001519
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001520 /* If we're going from non-connectable to connectable or
1521 * vice-versa when fast connectable is enabled ensure that fast
1522 * connectable gets disabled. write_fast_connectable won't do
1523 * anything if the page scan parameters are already what they
1524 * should be.
1525 */
1526 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001527 write_fast_connectable(&req, false);
1528
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001529 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1530 hci_conn_num(hdev, LE_LINK) == 0) {
1531 disable_advertising(&req);
1532 enable_advertising(&req);
1533 }
1534
Johan Hedberg2b76f452013-03-15 17:07:04 -05001535 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001536 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001537 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001538 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03001539 err = set_connectable_update_settings(hdev, sk,
1540 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03001541 goto failed;
1542 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001543
1544failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001545 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001546 return err;
1547}
1548
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001549static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001550 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001551{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001552 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001553 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001554 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001555
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001556 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001557
Johan Hedberga7e80f22013-01-09 16:05:19 +02001558 if (cp->val != 0x00 && cp->val != 0x01)
1559 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1560 MGMT_STATUS_INVALID_PARAMS);
1561
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001562 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001563
1564 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001565 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001566 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001567 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001568
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001569 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001570 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001571 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001572
Marcel Holtmann55594352013-10-06 16:11:57 -07001573 if (changed)
1574 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001575
Marcel Holtmann55594352013-10-06 16:11:57 -07001576unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001577 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001578 return err;
1579}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001580
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001581static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1582 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001583{
1584 struct mgmt_mode *cp = data;
1585 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001586 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001587 int err;
1588
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001589 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001590
Johan Hedberge6fe7982013-10-02 15:45:22 +03001591 status = mgmt_bredr_support(hdev);
1592 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001593 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001594 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001595
Johan Hedberga7e80f22013-01-09 16:05:19 +02001596 if (cp->val != 0x00 && cp->val != 0x01)
1597 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1598 MGMT_STATUS_INVALID_PARAMS);
1599
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001600 hci_dev_lock(hdev);
1601
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001602 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001603 bool changed = false;
1604
1605 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001606 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001607 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1608 changed = true;
1609 }
1610
1611 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1612 if (err < 0)
1613 goto failed;
1614
1615 if (changed)
1616 err = new_settings(hdev, sk);
1617
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001618 goto failed;
1619 }
1620
1621 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001622 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001623 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001624 goto failed;
1625 }
1626
1627 val = !!cp->val;
1628
1629 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1630 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1631 goto failed;
1632 }
1633
1634 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1635 if (!cmd) {
1636 err = -ENOMEM;
1637 goto failed;
1638 }
1639
1640 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1641 if (err < 0) {
1642 mgmt_pending_remove(cmd);
1643 goto failed;
1644 }
1645
1646failed:
1647 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001648 return err;
1649}
1650
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001651static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001652{
1653 struct mgmt_mode *cp = data;
1654 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001655 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001656 int err;
1657
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001658 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001659
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001660 status = mgmt_bredr_support(hdev);
1661 if (status)
1662 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1663
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001664 if (!lmp_ssp_capable(hdev))
1665 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1666 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001667
Johan Hedberga7e80f22013-01-09 16:05:19 +02001668 if (cp->val != 0x00 && cp->val != 0x01)
1669 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1670 MGMT_STATUS_INVALID_PARAMS);
1671
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001672 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001673
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001674 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001675 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001676
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001677 if (cp->val) {
1678 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1679 &hdev->dev_flags);
1680 } else {
1681 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1682 &hdev->dev_flags);
1683 if (!changed)
1684 changed = test_and_clear_bit(HCI_HS_ENABLED,
1685 &hdev->dev_flags);
1686 else
1687 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001688 }
1689
1690 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1691 if (err < 0)
1692 goto failed;
1693
1694 if (changed)
1695 err = new_settings(hdev, sk);
1696
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001697 goto failed;
1698 }
1699
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001700 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1701 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001702 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1703 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001704 goto failed;
1705 }
1706
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001707 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001708 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1709 goto failed;
1710 }
1711
1712 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1713 if (!cmd) {
1714 err = -ENOMEM;
1715 goto failed;
1716 }
1717
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001718 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001719 if (err < 0) {
1720 mgmt_pending_remove(cmd);
1721 goto failed;
1722 }
1723
1724failed:
1725 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001726 return err;
1727}
1728
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001729static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001730{
1731 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001732 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001733 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001734 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001735
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001736 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001737
Johan Hedberge6fe7982013-10-02 15:45:22 +03001738 status = mgmt_bredr_support(hdev);
1739 if (status)
1740 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001741
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001742 if (!lmp_ssp_capable(hdev))
1743 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1744 MGMT_STATUS_NOT_SUPPORTED);
1745
1746 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1747 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1748 MGMT_STATUS_REJECTED);
1749
Johan Hedberga7e80f22013-01-09 16:05:19 +02001750 if (cp->val != 0x00 && cp->val != 0x01)
1751 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1752 MGMT_STATUS_INVALID_PARAMS);
1753
Marcel Holtmannee392692013-10-01 22:59:23 -07001754 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001755
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001756 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001757 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001758 } else {
1759 if (hdev_is_powered(hdev)) {
1760 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1761 MGMT_STATUS_REJECTED);
1762 goto unlock;
1763 }
1764
Marcel Holtmannee392692013-10-01 22:59:23 -07001765 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001766 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001767
1768 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1769 if (err < 0)
1770 goto unlock;
1771
1772 if (changed)
1773 err = new_settings(hdev, sk);
1774
1775unlock:
1776 hci_dev_unlock(hdev);
1777 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001778}
1779
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001780static void le_enable_complete(struct hci_dev *hdev, u8 status)
1781{
1782 struct cmd_lookup match = { NULL, hdev };
1783
1784 if (status) {
1785 u8 mgmt_err = mgmt_status(status);
1786
1787 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1788 &mgmt_err);
1789 return;
1790 }
1791
1792 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1793
1794 new_settings(hdev, match.sk);
1795
1796 if (match.sk)
1797 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001798
1799 /* Make sure the controller has a good default for
1800 * advertising data. Restrict the update to when LE
1801 * has actually been enabled. During power on, the
1802 * update in powered_update_hci will take care of it.
1803 */
1804 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1805 struct hci_request req;
1806
1807 hci_dev_lock(hdev);
1808
1809 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001810 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07001811 update_scan_rsp_data(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001812 hci_req_run(&req, NULL);
1813
1814 hci_dev_unlock(hdev);
1815 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001816}
1817
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001818static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001819{
1820 struct mgmt_mode *cp = data;
1821 struct hci_cp_write_le_host_supported hci_cp;
1822 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001823 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001824 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001825 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001826
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001827 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001828
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001829 if (!lmp_le_capable(hdev))
1830 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1831 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001832
Johan Hedberga7e80f22013-01-09 16:05:19 +02001833 if (cp->val != 0x00 && cp->val != 0x01)
1834 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1835 MGMT_STATUS_INVALID_PARAMS);
1836
Johan Hedbergc73eee92013-04-19 18:35:21 +03001837 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001838 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001839 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1840 MGMT_STATUS_REJECTED);
1841
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001842 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001843
1844 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001845 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001846
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001847 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001848 bool changed = false;
1849
1850 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1851 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1852 changed = true;
1853 }
1854
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001855 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1856 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001857 changed = true;
1858 }
1859
Johan Hedberg06199cf2012-02-22 16:37:11 +02001860 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1861 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001862 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001863
1864 if (changed)
1865 err = new_settings(hdev, sk);
1866
Johan Hedberg1de028c2012-02-29 19:55:35 -08001867 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001868 }
1869
Johan Hedberg4375f102013-09-25 13:26:10 +03001870 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1871 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001872 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001873 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001874 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001875 }
1876
1877 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1878 if (!cmd) {
1879 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001880 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001881 }
1882
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001883 hci_req_init(&req, hdev);
1884
Johan Hedberg06199cf2012-02-22 16:37:11 +02001885 memset(&hci_cp, 0, sizeof(hci_cp));
1886
1887 if (val) {
1888 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001889 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001890 } else {
1891 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1892 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001893 }
1894
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001895 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1896 &hci_cp);
1897
1898 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301899 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001900 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001901
Johan Hedberg1de028c2012-02-29 19:55:35 -08001902unlock:
1903 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001904 return err;
1905}
1906
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001907/* This is a helper function to test for pending mgmt commands that can
1908 * cause CoD or EIR HCI commands. We can only allow one such pending
1909 * mgmt command at a time since otherwise we cannot easily track what
1910 * the current values are, will be, and based on that calculate if a new
1911 * HCI command needs to be sent and if yes with what value.
1912 */
1913static bool pending_eir_or_class(struct hci_dev *hdev)
1914{
1915 struct pending_cmd *cmd;
1916
1917 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1918 switch (cmd->opcode) {
1919 case MGMT_OP_ADD_UUID:
1920 case MGMT_OP_REMOVE_UUID:
1921 case MGMT_OP_SET_DEV_CLASS:
1922 case MGMT_OP_SET_POWERED:
1923 return true;
1924 }
1925 }
1926
1927 return false;
1928}
1929
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001930static const u8 bluetooth_base_uuid[] = {
1931 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1932 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1933};
1934
1935static u8 get_uuid_size(const u8 *uuid)
1936{
1937 u32 val;
1938
1939 if (memcmp(uuid, bluetooth_base_uuid, 12))
1940 return 128;
1941
1942 val = get_unaligned_le32(&uuid[12]);
1943 if (val > 0xffff)
1944 return 32;
1945
1946 return 16;
1947}
1948
Johan Hedberg92da6092013-03-15 17:06:55 -05001949static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1950{
1951 struct pending_cmd *cmd;
1952
1953 hci_dev_lock(hdev);
1954
1955 cmd = mgmt_pending_find(mgmt_op, hdev);
1956 if (!cmd)
1957 goto unlock;
1958
1959 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1960 hdev->dev_class, 3);
1961
1962 mgmt_pending_remove(cmd);
1963
1964unlock:
1965 hci_dev_unlock(hdev);
1966}
1967
1968static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1969{
1970 BT_DBG("status 0x%02x", status);
1971
1972 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1973}
1974
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001975static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001976{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001977 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001978 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001979 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001980 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001981 int err;
1982
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001983 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001984
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001985 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001986
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001987 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001988 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001989 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001990 goto failed;
1991 }
1992
Andre Guedes92c4c202012-06-07 19:05:44 -03001993 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001994 if (!uuid) {
1995 err = -ENOMEM;
1996 goto failed;
1997 }
1998
1999 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002000 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002001 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002002
Johan Hedbergde66aa62013-01-27 00:31:27 +02002003 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002004
Johan Hedberg890ea892013-03-15 17:06:52 -05002005 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002006
Johan Hedberg890ea892013-03-15 17:06:52 -05002007 update_class(&req);
2008 update_eir(&req);
2009
Johan Hedberg92da6092013-03-15 17:06:55 -05002010 err = hci_req_run(&req, add_uuid_complete);
2011 if (err < 0) {
2012 if (err != -ENODATA)
2013 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002014
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002015 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002016 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002017 goto failed;
2018 }
2019
2020 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002021 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002022 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002023 goto failed;
2024 }
2025
2026 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002027
2028failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002029 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002030 return err;
2031}
2032
Johan Hedberg24b78d02012-02-23 23:24:30 +02002033static bool enable_service_cache(struct hci_dev *hdev)
2034{
2035 if (!hdev_is_powered(hdev))
2036 return false;
2037
2038 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002039 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2040 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002041 return true;
2042 }
2043
2044 return false;
2045}
2046
Johan Hedberg92da6092013-03-15 17:06:55 -05002047static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
2048{
2049 BT_DBG("status 0x%02x", status);
2050
2051 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2052}
2053
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002054static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002055 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002056{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002057 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002058 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002059 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002060 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 -05002061 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002062 int err, found;
2063
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002064 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002065
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002066 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002067
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002068 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002069 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002070 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002071 goto unlock;
2072 }
2073
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002074 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
2075 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002076
Johan Hedberg24b78d02012-02-23 23:24:30 +02002077 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002078 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002079 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002080 goto unlock;
2081 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002082
Johan Hedberg9246a862012-02-23 21:33:16 +02002083 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002084 }
2085
2086 found = 0;
2087
Johan Hedberg056341c2013-01-27 00:31:30 +02002088 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002089 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2090 continue;
2091
2092 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002093 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002094 found++;
2095 }
2096
2097 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002098 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002099 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002100 goto unlock;
2101 }
2102
Johan Hedberg9246a862012-02-23 21:33:16 +02002103update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002104 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002105
Johan Hedberg890ea892013-03-15 17:06:52 -05002106 update_class(&req);
2107 update_eir(&req);
2108
Johan Hedberg92da6092013-03-15 17:06:55 -05002109 err = hci_req_run(&req, remove_uuid_complete);
2110 if (err < 0) {
2111 if (err != -ENODATA)
2112 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002113
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002114 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002115 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002116 goto unlock;
2117 }
2118
2119 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002120 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002121 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002122 goto unlock;
2123 }
2124
2125 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002126
2127unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002128 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002129 return err;
2130}
2131
Johan Hedberg92da6092013-03-15 17:06:55 -05002132static void set_class_complete(struct hci_dev *hdev, u8 status)
2133{
2134 BT_DBG("status 0x%02x", status);
2135
2136 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2137}
2138
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002139static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002140 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002141{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002142 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002143 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002144 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002145 int err;
2146
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002147 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002148
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002149 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002150 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2151 MGMT_STATUS_NOT_SUPPORTED);
2152
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002153 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002154
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002155 if (pending_eir_or_class(hdev)) {
2156 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2157 MGMT_STATUS_BUSY);
2158 goto unlock;
2159 }
2160
2161 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2162 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2163 MGMT_STATUS_INVALID_PARAMS);
2164 goto unlock;
2165 }
2166
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002167 hdev->major_class = cp->major;
2168 hdev->minor_class = cp->minor;
2169
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002170 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002171 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002172 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002173 goto unlock;
2174 }
2175
Johan Hedberg890ea892013-03-15 17:06:52 -05002176 hci_req_init(&req, hdev);
2177
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002178 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002179 hci_dev_unlock(hdev);
2180 cancel_delayed_work_sync(&hdev->service_cache);
2181 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002182 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002183 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002184
Johan Hedberg890ea892013-03-15 17:06:52 -05002185 update_class(&req);
2186
Johan Hedberg92da6092013-03-15 17:06:55 -05002187 err = hci_req_run(&req, set_class_complete);
2188 if (err < 0) {
2189 if (err != -ENODATA)
2190 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002191
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002192 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002193 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002194 goto unlock;
2195 }
2196
2197 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002198 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002199 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002200 goto unlock;
2201 }
2202
2203 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002204
Johan Hedbergb5235a62012-02-21 14:32:24 +02002205unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002206 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002207 return err;
2208}
2209
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002210static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002211 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002212{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002213 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002214 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002215 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002216
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002217 BT_DBG("request for %s", hdev->name);
2218
2219 if (!lmp_bredr_capable(hdev))
2220 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2221 MGMT_STATUS_NOT_SUPPORTED);
2222
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002223 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002224
Johan Hedberg86742e12011-11-07 23:13:38 +02002225 expected_len = sizeof(*cp) + key_count *
2226 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002227 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002228 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002229 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002230 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002231 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002232 }
2233
Johan Hedberg4ae143012013-01-20 14:27:13 +02002234 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2235 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2236 MGMT_STATUS_INVALID_PARAMS);
2237
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002238 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002239 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002240
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002241 for (i = 0; i < key_count; i++) {
2242 struct mgmt_link_key_info *key = &cp->keys[i];
2243
Marcel Holtmann8e991132014-01-10 02:07:25 -08002244 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002245 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2246 MGMT_STATUS_INVALID_PARAMS);
2247 }
2248
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002249 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002250
2251 hci_link_keys_clear(hdev);
2252
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002253 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002254 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002255 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002256 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002257
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002258 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002259 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002260
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002261 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002262 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002263 }
2264
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002265 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002266
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002267 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002268
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002269 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002270}
2271
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002272static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002273 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002274{
2275 struct mgmt_ev_device_unpaired ev;
2276
2277 bacpy(&ev.addr.bdaddr, bdaddr);
2278 ev.addr.type = addr_type;
2279
2280 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002281 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002282}
2283
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002284static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002285 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002286{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002287 struct mgmt_cp_unpair_device *cp = data;
2288 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002289 struct hci_cp_disconnect dc;
2290 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002291 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002292 int err;
2293
Johan Hedberga8a1d192011-11-10 15:54:38 +02002294 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002295 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2296 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002297
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002298 if (!bdaddr_type_is_valid(cp->addr.type))
2299 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2300 MGMT_STATUS_INVALID_PARAMS,
2301 &rp, sizeof(rp));
2302
Johan Hedberg118da702013-01-20 14:27:20 +02002303 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2304 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2305 MGMT_STATUS_INVALID_PARAMS,
2306 &rp, sizeof(rp));
2307
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002308 hci_dev_lock(hdev);
2309
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002310 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002311 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002312 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002313 goto unlock;
2314 }
2315
Andre Guedes591f47f2012-04-24 21:02:49 -03002316 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02002317 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
2318 else
2319 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002320
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002321 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002322 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002323 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002324 goto unlock;
2325 }
2326
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002327 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002328 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002329 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002330 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002331 else
2332 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002333 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002334 } else {
2335 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002336 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002337
Johan Hedberga8a1d192011-11-10 15:54:38 +02002338 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002339 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002340 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002341 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002342 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002343 }
2344
Johan Hedberg124f6e32012-02-09 13:50:12 +02002345 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002346 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002347 if (!cmd) {
2348 err = -ENOMEM;
2349 goto unlock;
2350 }
2351
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002352 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002353 dc.reason = 0x13; /* Remote User Terminated Connection */
2354 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2355 if (err < 0)
2356 mgmt_pending_remove(cmd);
2357
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002358unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002359 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002360 return err;
2361}
2362
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002363static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002364 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002365{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002366 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002367 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002368 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002369 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002370 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002371 int err;
2372
2373 BT_DBG("");
2374
Johan Hedberg06a63b12013-01-20 14:27:21 +02002375 memset(&rp, 0, sizeof(rp));
2376 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2377 rp.addr.type = cp->addr.type;
2378
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002379 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002380 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2381 MGMT_STATUS_INVALID_PARAMS,
2382 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002383
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002384 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002385
2386 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002387 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2388 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002389 goto failed;
2390 }
2391
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002392 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002393 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2394 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002395 goto failed;
2396 }
2397
Andre Guedes591f47f2012-04-24 21:02:49 -03002398 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002399 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2400 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002401 else
2402 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002403
Vishal Agarwalf9607272012-06-13 05:32:43 +05302404 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002405 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2406 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002407 goto failed;
2408 }
2409
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002410 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002411 if (!cmd) {
2412 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002413 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002414 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002415
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002416 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002417 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002418
2419 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2420 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002421 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002422
2423failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002424 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002425 return err;
2426}
2427
Andre Guedes57c14772012-04-24 21:02:50 -03002428static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002429{
2430 switch (link_type) {
2431 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002432 switch (addr_type) {
2433 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002434 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002435
Johan Hedberg48264f02011-11-09 13:58:58 +02002436 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002437 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002438 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002439 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002440
Johan Hedberg4c659c32011-11-07 23:13:39 +02002441 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002442 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002443 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002444 }
2445}
2446
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002447static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2448 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002449{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002450 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002451 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002452 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002453 int err;
2454 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002455
2456 BT_DBG("");
2457
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002458 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002459
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002460 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002461 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002462 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002463 goto unlock;
2464 }
2465
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002466 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002467 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2468 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002469 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002470 }
2471
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002472 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002473 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002474 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002475 err = -ENOMEM;
2476 goto unlock;
2477 }
2478
Johan Hedberg2784eb42011-01-21 13:56:35 +02002479 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002480 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002481 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2482 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002483 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002484 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002485 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002486 continue;
2487 i++;
2488 }
2489
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002490 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002491
Johan Hedberg4c659c32011-11-07 23:13:39 +02002492 /* Recalculate length in case of filtered SCO connections, etc */
2493 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002494
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002495 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002496 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002497
Johan Hedberga38528f2011-01-22 06:46:43 +02002498 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002499
2500unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002501 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002502 return err;
2503}
2504
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002505static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002506 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002507{
2508 struct pending_cmd *cmd;
2509 int err;
2510
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002511 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002512 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002513 if (!cmd)
2514 return -ENOMEM;
2515
Johan Hedbergd8457692012-02-17 14:24:57 +02002516 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002517 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002518 if (err < 0)
2519 mgmt_pending_remove(cmd);
2520
2521 return err;
2522}
2523
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002524static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002525 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002526{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002527 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002528 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002529 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002530 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002531 int err;
2532
2533 BT_DBG("");
2534
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002535 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002536
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002537 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002538 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002539 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002540 goto failed;
2541 }
2542
Johan Hedbergd8457692012-02-17 14:24:57 +02002543 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002544 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002545 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002546 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002547 goto failed;
2548 }
2549
2550 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002551 struct mgmt_cp_pin_code_neg_reply ncp;
2552
2553 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002554
2555 BT_ERR("PIN code is not 16 bytes long");
2556
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002557 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002558 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002559 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002560 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002561
2562 goto failed;
2563 }
2564
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002565 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002566 if (!cmd) {
2567 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002568 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002569 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002570
Johan Hedbergd8457692012-02-17 14:24:57 +02002571 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002572 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002573 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002574
2575 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2576 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002577 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002578
2579failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002580 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002581 return err;
2582}
2583
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002584static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2585 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002586{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002587 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002588
2589 BT_DBG("");
2590
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002591 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002592
2593 hdev->io_capability = cp->io_capability;
2594
2595 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002596 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002597
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002598 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002599
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002600 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2601 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002602}
2603
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002604static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002605{
2606 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002607 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002608
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002609 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002610 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2611 continue;
2612
Johan Hedberge9a416b2011-02-19 12:05:56 -03002613 if (cmd->user_data != conn)
2614 continue;
2615
2616 return cmd;
2617 }
2618
2619 return NULL;
2620}
2621
2622static void pairing_complete(struct pending_cmd *cmd, u8 status)
2623{
2624 struct mgmt_rp_pair_device rp;
2625 struct hci_conn *conn = cmd->user_data;
2626
Johan Hedbergba4e5642011-11-11 00:07:34 +02002627 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002628 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002629
Johan Hedbergaee9b212012-02-18 15:07:59 +02002630 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002631 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002632
2633 /* So we don't get further callbacks for this connection */
2634 conn->connect_cfm_cb = NULL;
2635 conn->security_cfm_cb = NULL;
2636 conn->disconn_cfm_cb = NULL;
2637
David Herrmann76a68ba2013-04-06 20:28:37 +02002638 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002639
Johan Hedberga664b5b2011-02-19 12:06:02 -03002640 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002641}
2642
2643static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2644{
2645 struct pending_cmd *cmd;
2646
2647 BT_DBG("status %u", status);
2648
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002649 cmd = find_pairing(conn);
2650 if (!cmd)
2651 BT_DBG("Unable to find a pending command");
2652 else
Johan Hedberge2113262012-02-18 15:20:03 +02002653 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002654}
2655
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302656static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2657{
2658 struct pending_cmd *cmd;
2659
2660 BT_DBG("status %u", status);
2661
2662 if (!status)
2663 return;
2664
2665 cmd = find_pairing(conn);
2666 if (!cmd)
2667 BT_DBG("Unable to find a pending command");
2668 else
2669 pairing_complete(cmd, mgmt_status(status));
2670}
2671
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002672static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002673 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002674{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002675 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002676 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002677 struct pending_cmd *cmd;
2678 u8 sec_level, auth_type;
2679 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002680 int err;
2681
2682 BT_DBG("");
2683
Szymon Jancf950a30e2013-01-18 12:48:07 +01002684 memset(&rp, 0, sizeof(rp));
2685 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2686 rp.addr.type = cp->addr.type;
2687
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002688 if (!bdaddr_type_is_valid(cp->addr.type))
2689 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2690 MGMT_STATUS_INVALID_PARAMS,
2691 &rp, sizeof(rp));
2692
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002693 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002694
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002695 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002696 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2697 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002698 goto unlock;
2699 }
2700
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002701 sec_level = BT_SECURITY_MEDIUM;
2702 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002703 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002704 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002705 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002706
Andre Guedes591f47f2012-04-24 21:02:49 -03002707 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002708 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2709 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002710 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002711 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2712 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002713
Ville Tervo30e76272011-02-22 16:10:53 -03002714 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002715 int status;
2716
2717 if (PTR_ERR(conn) == -EBUSY)
2718 status = MGMT_STATUS_BUSY;
2719 else
2720 status = MGMT_STATUS_CONNECT_FAILED;
2721
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002722 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002723 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002724 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002725 goto unlock;
2726 }
2727
2728 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002729 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002730 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002731 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002732 goto unlock;
2733 }
2734
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002735 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002736 if (!cmd) {
2737 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002738 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002739 goto unlock;
2740 }
2741
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002742 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002743 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002744 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302745 else
2746 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002747
Johan Hedberge9a416b2011-02-19 12:05:56 -03002748 conn->security_cfm_cb = pairing_complete_cb;
2749 conn->disconn_cfm_cb = pairing_complete_cb;
2750 conn->io_capability = cp->io_cap;
2751 cmd->user_data = conn;
2752
2753 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002754 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002755 pairing_complete(cmd, 0);
2756
2757 err = 0;
2758
2759unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002760 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002761 return err;
2762}
2763
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002764static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2765 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002766{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002767 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002768 struct pending_cmd *cmd;
2769 struct hci_conn *conn;
2770 int err;
2771
2772 BT_DBG("");
2773
Johan Hedberg28424702012-02-02 04:02:29 +02002774 hci_dev_lock(hdev);
2775
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002776 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002777 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002778 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002779 goto unlock;
2780 }
2781
Johan Hedberg28424702012-02-02 04:02:29 +02002782 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2783 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002784 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002785 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002786 goto unlock;
2787 }
2788
2789 conn = cmd->user_data;
2790
2791 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002792 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002793 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002794 goto unlock;
2795 }
2796
2797 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2798
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002799 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002800 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002801unlock:
2802 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002803 return err;
2804}
2805
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002806static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002807 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002808 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002809{
Johan Hedberga5c29682011-02-19 12:05:57 -03002810 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002811 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002812 int err;
2813
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002814 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002815
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002816 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002817 err = cmd_complete(sk, hdev->id, mgmt_op,
2818 MGMT_STATUS_NOT_POWERED, addr,
2819 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002820 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002821 }
2822
Johan Hedberg1707c602013-03-15 17:07:15 -05002823 if (addr->type == BDADDR_BREDR)
2824 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002825 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002826 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002827
Johan Hedberg272d90d2012-02-09 15:26:12 +02002828 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002829 err = cmd_complete(sk, hdev->id, mgmt_op,
2830 MGMT_STATUS_NOT_CONNECTED, addr,
2831 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002832 goto done;
2833 }
2834
Johan Hedberg1707c602013-03-15 17:07:15 -05002835 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002836 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002837 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002838
Brian Gix5fe57d92011-12-21 16:12:13 -08002839 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002840 err = cmd_complete(sk, hdev->id, mgmt_op,
2841 MGMT_STATUS_SUCCESS, addr,
2842 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002843 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002844 err = cmd_complete(sk, hdev->id, mgmt_op,
2845 MGMT_STATUS_FAILED, addr,
2846 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002847
Brian Gix47c15e22011-11-16 13:53:14 -08002848 goto done;
2849 }
2850
Johan Hedberg1707c602013-03-15 17:07:15 -05002851 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002852 if (!cmd) {
2853 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002854 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002855 }
2856
Brian Gix0df4c182011-11-16 13:53:13 -08002857 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002858 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2859 struct hci_cp_user_passkey_reply cp;
2860
Johan Hedberg1707c602013-03-15 17:07:15 -05002861 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002862 cp.passkey = passkey;
2863 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2864 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002865 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2866 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002867
Johan Hedberga664b5b2011-02-19 12:06:02 -03002868 if (err < 0)
2869 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002870
Brian Gix0df4c182011-11-16 13:53:13 -08002871done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002872 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002873 return err;
2874}
2875
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302876static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2877 void *data, u16 len)
2878{
2879 struct mgmt_cp_pin_code_neg_reply *cp = data;
2880
2881 BT_DBG("");
2882
Johan Hedberg1707c602013-03-15 17:07:15 -05002883 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302884 MGMT_OP_PIN_CODE_NEG_REPLY,
2885 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2886}
2887
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002888static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2889 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002890{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002891 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002892
2893 BT_DBG("");
2894
2895 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002896 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002897 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002898
Johan Hedberg1707c602013-03-15 17:07:15 -05002899 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002900 MGMT_OP_USER_CONFIRM_REPLY,
2901 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002902}
2903
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002904static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002905 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002906{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002907 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002908
2909 BT_DBG("");
2910
Johan Hedberg1707c602013-03-15 17:07:15 -05002911 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002912 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2913 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002914}
2915
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002916static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2917 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002918{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002919 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002920
2921 BT_DBG("");
2922
Johan Hedberg1707c602013-03-15 17:07:15 -05002923 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002924 MGMT_OP_USER_PASSKEY_REPLY,
2925 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002926}
2927
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002928static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002929 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002930{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002931 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002932
2933 BT_DBG("");
2934
Johan Hedberg1707c602013-03-15 17:07:15 -05002935 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002936 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2937 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002938}
2939
Johan Hedberg13928972013-03-15 17:07:00 -05002940static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002941{
Johan Hedberg13928972013-03-15 17:07:00 -05002942 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002943 struct hci_cp_write_local_name cp;
2944
Johan Hedberg13928972013-03-15 17:07:00 -05002945 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002946
Johan Hedberg890ea892013-03-15 17:06:52 -05002947 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002948}
2949
Johan Hedberg13928972013-03-15 17:07:00 -05002950static void set_name_complete(struct hci_dev *hdev, u8 status)
2951{
2952 struct mgmt_cp_set_local_name *cp;
2953 struct pending_cmd *cmd;
2954
2955 BT_DBG("status 0x%02x", status);
2956
2957 hci_dev_lock(hdev);
2958
2959 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2960 if (!cmd)
2961 goto unlock;
2962
2963 cp = cmd->param;
2964
2965 if (status)
2966 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2967 mgmt_status(status));
2968 else
2969 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2970 cp, sizeof(*cp));
2971
2972 mgmt_pending_remove(cmd);
2973
2974unlock:
2975 hci_dev_unlock(hdev);
2976}
2977
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002978static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002979 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002980{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002981 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002982 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002983 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002984 int err;
2985
2986 BT_DBG("");
2987
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002988 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002989
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002990 /* If the old values are the same as the new ones just return a
2991 * direct command complete event.
2992 */
2993 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2994 !memcmp(hdev->short_name, cp->short_name,
2995 sizeof(hdev->short_name))) {
2996 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2997 data, len);
2998 goto failed;
2999 }
3000
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003001 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003002
Johan Hedbergb5235a62012-02-21 14:32:24 +02003003 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003004 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003005
3006 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003007 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003008 if (err < 0)
3009 goto failed;
3010
3011 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003012 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003013
Johan Hedbergb5235a62012-02-21 14:32:24 +02003014 goto failed;
3015 }
3016
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003017 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003018 if (!cmd) {
3019 err = -ENOMEM;
3020 goto failed;
3021 }
3022
Johan Hedberg13928972013-03-15 17:07:00 -05003023 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3024
Johan Hedberg890ea892013-03-15 17:06:52 -05003025 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003026
3027 if (lmp_bredr_capable(hdev)) {
3028 update_name(&req);
3029 update_eir(&req);
3030 }
3031
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003032 /* The name is stored in the scan response data and so
3033 * no need to udpate the advertising data here.
3034 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003035 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003036 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003037
Johan Hedberg13928972013-03-15 17:07:00 -05003038 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003039 if (err < 0)
3040 mgmt_pending_remove(cmd);
3041
3042failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003043 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003044 return err;
3045}
3046
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003047static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003048 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003049{
Szymon Jancc35938b2011-03-22 13:12:21 +01003050 struct pending_cmd *cmd;
3051 int err;
3052
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003053 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003054
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003055 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003056
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003057 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003058 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003059 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003060 goto unlock;
3061 }
3062
Andre Guedes9a1a1992012-07-24 15:03:48 -03003063 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003064 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003065 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003066 goto unlock;
3067 }
3068
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003069 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003070 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003071 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003072 goto unlock;
3073 }
3074
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003075 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003076 if (!cmd) {
3077 err = -ENOMEM;
3078 goto unlock;
3079 }
3080
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003081 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
3082 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
3083 0, NULL);
3084 else
3085 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3086
Szymon Jancc35938b2011-03-22 13:12:21 +01003087 if (err < 0)
3088 mgmt_pending_remove(cmd);
3089
3090unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003091 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003092 return err;
3093}
3094
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003095static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003096 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003097{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003098 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003099 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003100 int err;
3101
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003102 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003103
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003104 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003105
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003106 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003107 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01003108 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003109 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01003110 else
Szymon Janca6785be2012-12-13 15:11:21 +01003111 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003112
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003113 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003114 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003115
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003116 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003117 return err;
3118}
3119
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003120static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003121 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003122{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003123 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003124 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003125 int err;
3126
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003127 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003128
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003129 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003130
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003131 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003132 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003133 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003134 else
Szymon Janca6785be2012-12-13 15:11:21 +01003135 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003136
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003137 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003138 status, &cp->addr, sizeof(cp->addr));
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
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003144static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3145{
3146 struct pending_cmd *cmd;
3147 u8 type;
3148 int err;
3149
3150 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3151
3152 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3153 if (!cmd)
3154 return -ENOENT;
3155
3156 type = hdev->discovery.type;
3157
3158 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3159 &type, sizeof(type));
3160 mgmt_pending_remove(cmd);
3161
3162 return err;
3163}
3164
Andre Guedes7c307722013-04-30 15:29:28 -03003165static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3166{
3167 BT_DBG("status %d", status);
3168
3169 if (status) {
3170 hci_dev_lock(hdev);
3171 mgmt_start_discovery_failed(hdev, status);
3172 hci_dev_unlock(hdev);
3173 return;
3174 }
3175
3176 hci_dev_lock(hdev);
3177 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3178 hci_dev_unlock(hdev);
3179
3180 switch (hdev->discovery.type) {
3181 case DISCOV_TYPE_LE:
3182 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003183 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003184 break;
3185
3186 case DISCOV_TYPE_INTERLEAVED:
3187 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003188 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003189 break;
3190
3191 case DISCOV_TYPE_BREDR:
3192 break;
3193
3194 default:
3195 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3196 }
3197}
3198
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003199static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003200 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003201{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003202 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003203 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003204 struct hci_cp_le_set_scan_param param_cp;
3205 struct hci_cp_le_set_scan_enable enable_cp;
3206 struct hci_cp_inquiry inq_cp;
3207 struct hci_request req;
3208 /* General inquiry access code (GIAC) */
3209 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003210 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003211 int err;
3212
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003213 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003214
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003215 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003216
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003217 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003218 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003219 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003220 goto failed;
3221 }
3222
Andre Guedes642be6c2012-03-21 00:03:37 -03003223 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3224 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3225 MGMT_STATUS_BUSY);
3226 goto failed;
3227 }
3228
Johan Hedbergff9ef572012-01-04 14:23:45 +02003229 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003230 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003231 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003232 goto failed;
3233 }
3234
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003235 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003236 if (!cmd) {
3237 err = -ENOMEM;
3238 goto failed;
3239 }
3240
Andre Guedes4aab14e2012-02-17 20:39:36 -03003241 hdev->discovery.type = cp->type;
3242
Andre Guedes7c307722013-04-30 15:29:28 -03003243 hci_req_init(&req, hdev);
3244
Andre Guedes4aab14e2012-02-17 20:39:36 -03003245 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003246 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003247 status = mgmt_bredr_support(hdev);
3248 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003249 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003250 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003251 mgmt_pending_remove(cmd);
3252 goto failed;
3253 }
3254
Andre Guedes7c307722013-04-30 15:29:28 -03003255 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3256 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3257 MGMT_STATUS_BUSY);
3258 mgmt_pending_remove(cmd);
3259 goto failed;
3260 }
3261
3262 hci_inquiry_cache_flush(hdev);
3263
3264 memset(&inq_cp, 0, sizeof(inq_cp));
3265 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003266 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003267 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003268 break;
3269
3270 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003271 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003272 status = mgmt_le_support(hdev);
3273 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003274 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003275 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003276 mgmt_pending_remove(cmd);
3277 goto failed;
3278 }
3279
Andre Guedes7c307722013-04-30 15:29:28 -03003280 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003281 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003282 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3283 MGMT_STATUS_NOT_SUPPORTED);
3284 mgmt_pending_remove(cmd);
3285 goto failed;
3286 }
3287
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003288 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003289 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3290 MGMT_STATUS_REJECTED);
3291 mgmt_pending_remove(cmd);
3292 goto failed;
3293 }
3294
3295 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3296 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3297 MGMT_STATUS_BUSY);
3298 mgmt_pending_remove(cmd);
3299 goto failed;
3300 }
3301
3302 memset(&param_cp, 0, sizeof(param_cp));
3303 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003304 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3305 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmann79830f62013-10-18 16:38:09 -07003306 param_cp.own_address_type = hdev->own_addr_type;
Andre Guedes7c307722013-04-30 15:29:28 -03003307 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3308 &param_cp);
3309
3310 memset(&enable_cp, 0, sizeof(enable_cp));
3311 enable_cp.enable = LE_SCAN_ENABLE;
3312 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3313 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3314 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003315 break;
3316
Andre Guedesf39799f2012-02-17 20:39:35 -03003317 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003318 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3319 MGMT_STATUS_INVALID_PARAMS);
3320 mgmt_pending_remove(cmd);
3321 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003322 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003323
Andre Guedes7c307722013-04-30 15:29:28 -03003324 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003325 if (err < 0)
3326 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003327 else
3328 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003329
3330failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003331 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003332 return err;
3333}
3334
Andre Guedes1183fdc2013-04-30 15:29:35 -03003335static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3336{
3337 struct pending_cmd *cmd;
3338 int err;
3339
3340 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3341 if (!cmd)
3342 return -ENOENT;
3343
3344 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3345 &hdev->discovery.type, sizeof(hdev->discovery.type));
3346 mgmt_pending_remove(cmd);
3347
3348 return err;
3349}
3350
Andre Guedes0e05bba2013-04-30 15:29:33 -03003351static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3352{
3353 BT_DBG("status %d", status);
3354
3355 hci_dev_lock(hdev);
3356
3357 if (status) {
3358 mgmt_stop_discovery_failed(hdev, status);
3359 goto unlock;
3360 }
3361
3362 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3363
3364unlock:
3365 hci_dev_unlock(hdev);
3366}
3367
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003368static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003369 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003370{
Johan Hedbergd9306502012-02-20 23:25:18 +02003371 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003372 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003373 struct hci_cp_remote_name_req_cancel cp;
3374 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003375 struct hci_request req;
3376 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003377 int err;
3378
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003379 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003380
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003381 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003382
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003383 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003384 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003385 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3386 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003387 goto unlock;
3388 }
3389
3390 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003391 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003392 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3393 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003394 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003395 }
3396
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003397 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003398 if (!cmd) {
3399 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003400 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003401 }
3402
Andre Guedes0e05bba2013-04-30 15:29:33 -03003403 hci_req_init(&req, hdev);
3404
Andre Guedese0d9727e2012-03-20 15:15:36 -03003405 switch (hdev->discovery.state) {
3406 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003407 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3408 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3409 } else {
3410 cancel_delayed_work(&hdev->le_scan_disable);
3411
3412 memset(&enable_cp, 0, sizeof(enable_cp));
3413 enable_cp.enable = LE_SCAN_DISABLE;
3414 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3415 sizeof(enable_cp), &enable_cp);
3416 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003417
Andre Guedese0d9727e2012-03-20 15:15:36 -03003418 break;
3419
3420 case DISCOVERY_RESOLVING:
3421 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003422 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003423 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003424 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003425 err = cmd_complete(sk, hdev->id,
3426 MGMT_OP_STOP_DISCOVERY, 0,
3427 &mgmt_cp->type,
3428 sizeof(mgmt_cp->type));
3429 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3430 goto unlock;
3431 }
3432
3433 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003434 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3435 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003436
3437 break;
3438
3439 default:
3440 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003441
3442 mgmt_pending_remove(cmd);
3443 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3444 MGMT_STATUS_FAILED, &mgmt_cp->type,
3445 sizeof(mgmt_cp->type));
3446 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003447 }
3448
Andre Guedes0e05bba2013-04-30 15:29:33 -03003449 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003450 if (err < 0)
3451 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003452 else
3453 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003454
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003455unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003456 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003457 return err;
3458}
3459
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003460static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003461 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003462{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003463 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003464 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003465 int err;
3466
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003467 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003468
Johan Hedberg561aafb2012-01-04 13:31:59 +02003469 hci_dev_lock(hdev);
3470
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003471 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003472 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003473 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003474 goto failed;
3475 }
3476
Johan Hedberga198e7b2012-02-17 14:27:06 +02003477 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003478 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003479 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003480 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003481 goto failed;
3482 }
3483
3484 if (cp->name_known) {
3485 e->name_state = NAME_KNOWN;
3486 list_del(&e->list);
3487 } else {
3488 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02003489 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003490 }
3491
Johan Hedberge3846622013-01-09 15:29:33 +02003492 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3493 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003494
3495failed:
3496 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003497 return err;
3498}
3499
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003500static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003501 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003502{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003503 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003504 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003505 int err;
3506
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003507 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003508
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003509 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003510 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3511 MGMT_STATUS_INVALID_PARAMS,
3512 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003513
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003514 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003515
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003516 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003517 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003518 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003519 else
Szymon Janca6785be2012-12-13 15:11:21 +01003520 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003521
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003522 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003523 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003524
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003525 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003526
3527 return err;
3528}
3529
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003530static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003531 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003532{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003533 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003534 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003535 int err;
3536
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003537 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003538
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003539 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003540 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3541 MGMT_STATUS_INVALID_PARAMS,
3542 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003543
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003544 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003545
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003546 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003547 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003548 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003549 else
Szymon Janca6785be2012-12-13 15:11:21 +01003550 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003551
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003552 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003553 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003554
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003555 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003556
3557 return err;
3558}
3559
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003560static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3561 u16 len)
3562{
3563 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003564 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003565 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003566 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003567
3568 BT_DBG("%s", hdev->name);
3569
Szymon Jancc72d4b82012-03-16 16:02:57 +01003570 source = __le16_to_cpu(cp->source);
3571
3572 if (source > 0x0002)
3573 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3574 MGMT_STATUS_INVALID_PARAMS);
3575
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003576 hci_dev_lock(hdev);
3577
Szymon Jancc72d4b82012-03-16 16:02:57 +01003578 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003579 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3580 hdev->devid_product = __le16_to_cpu(cp->product);
3581 hdev->devid_version = __le16_to_cpu(cp->version);
3582
3583 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3584
Johan Hedberg890ea892013-03-15 17:06:52 -05003585 hci_req_init(&req, hdev);
3586 update_eir(&req);
3587 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003588
3589 hci_dev_unlock(hdev);
3590
3591 return err;
3592}
3593
Johan Hedberg4375f102013-09-25 13:26:10 +03003594static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3595{
3596 struct cmd_lookup match = { NULL, hdev };
3597
3598 if (status) {
3599 u8 mgmt_err = mgmt_status(status);
3600
3601 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3602 cmd_status_rsp, &mgmt_err);
3603 return;
3604 }
3605
3606 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3607 &match);
3608
3609 new_settings(hdev, match.sk);
3610
3611 if (match.sk)
3612 sock_put(match.sk);
3613}
3614
Marcel Holtmann21b51872013-10-10 09:47:53 -07003615static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3616 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003617{
3618 struct mgmt_mode *cp = data;
3619 struct pending_cmd *cmd;
3620 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003621 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003622 int err;
3623
3624 BT_DBG("request for %s", hdev->name);
3625
Johan Hedberge6fe7982013-10-02 15:45:22 +03003626 status = mgmt_le_support(hdev);
3627 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003628 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003629 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003630
3631 if (cp->val != 0x00 && cp->val != 0x01)
3632 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3633 MGMT_STATUS_INVALID_PARAMS);
3634
3635 hci_dev_lock(hdev);
3636
3637 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003638 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003639
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003640 /* The following conditions are ones which mean that we should
3641 * not do any HCI communication but directly send a mgmt
3642 * response to user space (after toggling the flag if
3643 * necessary).
3644 */
3645 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003646 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003647 bool changed = false;
3648
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003649 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3650 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003651 changed = true;
3652 }
3653
3654 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3655 if (err < 0)
3656 goto unlock;
3657
3658 if (changed)
3659 err = new_settings(hdev, sk);
3660
3661 goto unlock;
3662 }
3663
3664 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3665 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3666 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3667 MGMT_STATUS_BUSY);
3668 goto unlock;
3669 }
3670
3671 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3672 if (!cmd) {
3673 err = -ENOMEM;
3674 goto unlock;
3675 }
3676
3677 hci_req_init(&req, hdev);
3678
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003679 if (val)
3680 enable_advertising(&req);
3681 else
3682 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003683
3684 err = hci_req_run(&req, set_advertising_complete);
3685 if (err < 0)
3686 mgmt_pending_remove(cmd);
3687
3688unlock:
3689 hci_dev_unlock(hdev);
3690 return err;
3691}
3692
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003693static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3694 void *data, u16 len)
3695{
3696 struct mgmt_cp_set_static_address *cp = data;
3697 int err;
3698
3699 BT_DBG("%s", hdev->name);
3700
Marcel Holtmann62af4442013-10-02 22:10:32 -07003701 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003702 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003703 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003704
3705 if (hdev_is_powered(hdev))
3706 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3707 MGMT_STATUS_REJECTED);
3708
3709 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3710 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3711 return cmd_status(sk, hdev->id,
3712 MGMT_OP_SET_STATIC_ADDRESS,
3713 MGMT_STATUS_INVALID_PARAMS);
3714
3715 /* Two most significant bits shall be set */
3716 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3717 return cmd_status(sk, hdev->id,
3718 MGMT_OP_SET_STATIC_ADDRESS,
3719 MGMT_STATUS_INVALID_PARAMS);
3720 }
3721
3722 hci_dev_lock(hdev);
3723
3724 bacpy(&hdev->static_addr, &cp->bdaddr);
3725
3726 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3727
3728 hci_dev_unlock(hdev);
3729
3730 return err;
3731}
3732
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003733static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3734 void *data, u16 len)
3735{
3736 struct mgmt_cp_set_scan_params *cp = data;
3737 __u16 interval, window;
3738 int err;
3739
3740 BT_DBG("%s", hdev->name);
3741
3742 if (!lmp_le_capable(hdev))
3743 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3744 MGMT_STATUS_NOT_SUPPORTED);
3745
3746 interval = __le16_to_cpu(cp->interval);
3747
3748 if (interval < 0x0004 || interval > 0x4000)
3749 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3750 MGMT_STATUS_INVALID_PARAMS);
3751
3752 window = __le16_to_cpu(cp->window);
3753
3754 if (window < 0x0004 || window > 0x4000)
3755 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3756 MGMT_STATUS_INVALID_PARAMS);
3757
Marcel Holtmann899e1072013-10-14 09:55:32 -07003758 if (window > interval)
3759 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3760 MGMT_STATUS_INVALID_PARAMS);
3761
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003762 hci_dev_lock(hdev);
3763
3764 hdev->le_scan_interval = interval;
3765 hdev->le_scan_window = window;
3766
3767 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3768
3769 hci_dev_unlock(hdev);
3770
3771 return err;
3772}
3773
Johan Hedberg33e38b32013-03-15 17:07:05 -05003774static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3775{
3776 struct pending_cmd *cmd;
3777
3778 BT_DBG("status 0x%02x", status);
3779
3780 hci_dev_lock(hdev);
3781
3782 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3783 if (!cmd)
3784 goto unlock;
3785
3786 if (status) {
3787 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3788 mgmt_status(status));
3789 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003790 struct mgmt_mode *cp = cmd->param;
3791
3792 if (cp->val)
3793 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3794 else
3795 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3796
Johan Hedberg33e38b32013-03-15 17:07:05 -05003797 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3798 new_settings(hdev, cmd->sk);
3799 }
3800
3801 mgmt_pending_remove(cmd);
3802
3803unlock:
3804 hci_dev_unlock(hdev);
3805}
3806
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003807static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003808 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003809{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003810 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003811 struct pending_cmd *cmd;
3812 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003813 int err;
3814
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003815 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003816
Johan Hedberg56f87902013-10-02 13:43:13 +03003817 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3818 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003819 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3820 MGMT_STATUS_NOT_SUPPORTED);
3821
Johan Hedberga7e80f22013-01-09 16:05:19 +02003822 if (cp->val != 0x00 && cp->val != 0x01)
3823 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3824 MGMT_STATUS_INVALID_PARAMS);
3825
Johan Hedberg5400c042012-02-21 16:40:33 +02003826 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003827 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003828 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003829
3830 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003831 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003832 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003833
3834 hci_dev_lock(hdev);
3835
Johan Hedberg05cbf292013-03-15 17:07:07 -05003836 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3837 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3838 MGMT_STATUS_BUSY);
3839 goto unlock;
3840 }
3841
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003842 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3843 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3844 hdev);
3845 goto unlock;
3846 }
3847
Johan Hedberg33e38b32013-03-15 17:07:05 -05003848 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3849 data, len);
3850 if (!cmd) {
3851 err = -ENOMEM;
3852 goto unlock;
3853 }
3854
3855 hci_req_init(&req, hdev);
3856
Johan Hedberg406d7802013-03-15 17:07:09 -05003857 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003858
3859 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003860 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003861 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003862 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003863 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003864 }
3865
Johan Hedberg33e38b32013-03-15 17:07:05 -05003866unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003867 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003868
Antti Julkuf6422ec2011-06-22 13:11:56 +03003869 return err;
3870}
3871
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003872static void set_bredr_scan(struct hci_request *req)
3873{
3874 struct hci_dev *hdev = req->hdev;
3875 u8 scan = 0;
3876
3877 /* Ensure that fast connectable is disabled. This function will
3878 * not do anything if the page scan parameters are already what
3879 * they should be.
3880 */
3881 write_fast_connectable(req, false);
3882
3883 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3884 scan |= SCAN_PAGE;
3885 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3886 scan |= SCAN_INQUIRY;
3887
3888 if (scan)
3889 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3890}
3891
Johan Hedberg0663ca22013-10-02 13:43:14 +03003892static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3893{
3894 struct pending_cmd *cmd;
3895
3896 BT_DBG("status 0x%02x", status);
3897
3898 hci_dev_lock(hdev);
3899
3900 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3901 if (!cmd)
3902 goto unlock;
3903
3904 if (status) {
3905 u8 mgmt_err = mgmt_status(status);
3906
3907 /* We need to restore the flag if related HCI commands
3908 * failed.
3909 */
3910 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3911
3912 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3913 } else {
3914 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3915 new_settings(hdev, cmd->sk);
3916 }
3917
3918 mgmt_pending_remove(cmd);
3919
3920unlock:
3921 hci_dev_unlock(hdev);
3922}
3923
3924static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3925{
3926 struct mgmt_mode *cp = data;
3927 struct pending_cmd *cmd;
3928 struct hci_request req;
3929 int err;
3930
3931 BT_DBG("request for %s", hdev->name);
3932
3933 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3934 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3935 MGMT_STATUS_NOT_SUPPORTED);
3936
3937 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3938 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3939 MGMT_STATUS_REJECTED);
3940
3941 if (cp->val != 0x00 && cp->val != 0x01)
3942 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3943 MGMT_STATUS_INVALID_PARAMS);
3944
3945 hci_dev_lock(hdev);
3946
3947 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3948 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3949 goto unlock;
3950 }
3951
3952 if (!hdev_is_powered(hdev)) {
3953 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003954 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3955 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3956 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3957 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3958 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3959 }
3960
3961 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3962
3963 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3964 if (err < 0)
3965 goto unlock;
3966
3967 err = new_settings(hdev, sk);
3968 goto unlock;
3969 }
3970
3971 /* Reject disabling when powered on */
3972 if (!cp->val) {
3973 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3974 MGMT_STATUS_REJECTED);
3975 goto unlock;
3976 }
3977
3978 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3979 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3980 MGMT_STATUS_BUSY);
3981 goto unlock;
3982 }
3983
3984 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3985 if (!cmd) {
3986 err = -ENOMEM;
3987 goto unlock;
3988 }
3989
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07003990 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03003991 * generates the correct flags.
3992 */
3993 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3994
3995 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003996
3997 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3998 set_bredr_scan(&req);
3999
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004000 /* Since only the advertising data flags will change, there
4001 * is no need to update the scan response data.
4002 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004003 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004004
Johan Hedberg0663ca22013-10-02 13:43:14 +03004005 err = hci_req_run(&req, set_bredr_complete);
4006 if (err < 0)
4007 mgmt_pending_remove(cmd);
4008
4009unlock:
4010 hci_dev_unlock(hdev);
4011 return err;
4012}
4013
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004014static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4015 void *data, u16 len)
4016{
4017 struct mgmt_mode *cp = data;
4018 struct pending_cmd *cmd;
4019 u8 status;
4020 int err;
4021
4022 BT_DBG("request for %s", hdev->name);
4023
4024 status = mgmt_bredr_support(hdev);
4025 if (status)
4026 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4027 status);
4028
4029 if (!lmp_sc_capable(hdev))
4030 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4031 MGMT_STATUS_NOT_SUPPORTED);
4032
4033 if (cp->val != 0x00 && cp->val != 0x01)
4034 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4035 MGMT_STATUS_INVALID_PARAMS);
4036
4037 hci_dev_lock(hdev);
4038
4039 if (!hdev_is_powered(hdev)) {
4040 bool changed;
4041
4042 if (cp->val)
4043 changed = !test_and_set_bit(HCI_SC_ENABLED,
4044 &hdev->dev_flags);
4045 else
4046 changed = test_and_clear_bit(HCI_SC_ENABLED,
4047 &hdev->dev_flags);
4048
4049 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4050 if (err < 0)
4051 goto failed;
4052
4053 if (changed)
4054 err = new_settings(hdev, sk);
4055
4056 goto failed;
4057 }
4058
4059 if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
4060 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4061 MGMT_STATUS_BUSY);
4062 goto failed;
4063 }
4064
4065 if (!!cp->val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
4066 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4067 goto failed;
4068 }
4069
4070 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4071 if (!cmd) {
4072 err = -ENOMEM;
4073 goto failed;
4074 }
4075
4076 err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &cp->val);
4077 if (err < 0) {
4078 mgmt_pending_remove(cmd);
4079 goto failed;
4080 }
4081
4082failed:
4083 hci_dev_unlock(hdev);
4084 return err;
4085}
4086
Johan Hedberg3f706b72013-01-20 14:27:16 +02004087static bool ltk_is_valid(struct mgmt_ltk_info *key)
4088{
Johan Hedberg44b20d32013-01-20 14:27:17 +02004089 if (key->authenticated != 0x00 && key->authenticated != 0x01)
4090 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004091 if (key->master != 0x00 && key->master != 0x01)
4092 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004093 if (!bdaddr_type_is_le(key->addr.type))
4094 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004095 return true;
4096}
4097
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004098static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004099 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004100{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004101 struct mgmt_cp_load_long_term_keys *cp = cp_data;
4102 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004103 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004104
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004105 BT_DBG("request for %s", hdev->name);
4106
4107 if (!lmp_le_capable(hdev))
4108 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4109 MGMT_STATUS_NOT_SUPPORTED);
4110
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004111 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004112
4113 expected_len = sizeof(*cp) + key_count *
4114 sizeof(struct mgmt_ltk_info);
4115 if (expected_len != len) {
4116 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004117 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004118 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02004119 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004120 }
4121
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004122 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004123
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004124 for (i = 0; i < key_count; i++) {
4125 struct mgmt_ltk_info *key = &cp->keys[i];
4126
Johan Hedberg3f706b72013-01-20 14:27:16 +02004127 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004128 return cmd_status(sk, hdev->id,
4129 MGMT_OP_LOAD_LONG_TERM_KEYS,
4130 MGMT_STATUS_INVALID_PARAMS);
4131 }
4132
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004133 hci_dev_lock(hdev);
4134
4135 hci_smp_ltks_clear(hdev);
4136
4137 for (i = 0; i < key_count; i++) {
4138 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004139 u8 type, addr_type;
4140
4141 if (key->addr.type == BDADDR_LE_PUBLIC)
4142 addr_type = ADDR_LE_DEV_PUBLIC;
4143 else
4144 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004145
4146 if (key->master)
4147 type = HCI_SMP_LTK;
4148 else
4149 type = HCI_SMP_LTK_SLAVE;
4150
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004151 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004152 type, 0, key->authenticated, key->val,
4153 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004154 }
4155
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004156 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4157 NULL, 0);
4158
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004159 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004160
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004161 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004162}
4163
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004164static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004165 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4166 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004167 bool var_len;
4168 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004169} mgmt_handlers[] = {
4170 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004171 { read_version, false, MGMT_READ_VERSION_SIZE },
4172 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4173 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4174 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4175 { set_powered, false, MGMT_SETTING_SIZE },
4176 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4177 { set_connectable, false, MGMT_SETTING_SIZE },
4178 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4179 { set_pairable, false, MGMT_SETTING_SIZE },
4180 { set_link_security, false, MGMT_SETTING_SIZE },
4181 { set_ssp, false, MGMT_SETTING_SIZE },
4182 { set_hs, false, MGMT_SETTING_SIZE },
4183 { set_le, false, MGMT_SETTING_SIZE },
4184 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4185 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4186 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4187 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4188 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4189 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4190 { disconnect, false, MGMT_DISCONNECT_SIZE },
4191 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4192 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4193 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4194 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4195 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4196 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4197 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4198 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4199 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4200 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4201 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4202 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
4203 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
4204 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4205 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4206 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4207 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4208 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4209 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004210 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004211 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004212 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004213 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004214 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004215 { set_secure_conn, false, MGMT_SETTING_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004216};
4217
4218
Johan Hedberg03811012010-12-08 00:21:06 +02004219int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4220{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004221 void *buf;
4222 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004223 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004224 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004225 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004226 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004227 int err;
4228
4229 BT_DBG("got %zu bytes", msglen);
4230
4231 if (msglen < sizeof(*hdr))
4232 return -EINVAL;
4233
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004234 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004235 if (!buf)
4236 return -ENOMEM;
4237
4238 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4239 err = -EFAULT;
4240 goto done;
4241 }
4242
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004243 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004244 opcode = __le16_to_cpu(hdr->opcode);
4245 index = __le16_to_cpu(hdr->index);
4246 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004247
4248 if (len != msglen - sizeof(*hdr)) {
4249 err = -EINVAL;
4250 goto done;
4251 }
4252
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004253 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004254 hdev = hci_dev_get(index);
4255 if (!hdev) {
4256 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004257 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004258 goto done;
4259 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004260
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004261 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4262 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004263 err = cmd_status(sk, index, opcode,
4264 MGMT_STATUS_INVALID_INDEX);
4265 goto done;
4266 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004267 }
4268
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004269 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004270 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004271 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004272 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004273 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004274 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004275 }
4276
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004277 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004278 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004279 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004280 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004281 goto done;
4282 }
4283
Johan Hedbergbe22b542012-03-01 22:24:41 +02004284 handler = &mgmt_handlers[opcode];
4285
4286 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004287 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004288 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004289 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004290 goto done;
4291 }
4292
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004293 if (hdev)
4294 mgmt_init_hdev(sk, hdev);
4295
4296 cp = buf + sizeof(*hdr);
4297
Johan Hedbergbe22b542012-03-01 22:24:41 +02004298 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004299 if (err < 0)
4300 goto done;
4301
Johan Hedberg03811012010-12-08 00:21:06 +02004302 err = msglen;
4303
4304done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004305 if (hdev)
4306 hci_dev_put(hdev);
4307
Johan Hedberg03811012010-12-08 00:21:06 +02004308 kfree(buf);
4309 return err;
4310}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004311
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004312void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004313{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004314 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004315 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004316
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004317 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004318}
4319
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004320void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004321{
Johan Hedberg5f159032012-03-02 03:13:19 +02004322 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004323
Marcel Holtmann1514b892013-10-06 08:25:01 -07004324 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004325 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004326
Johan Hedberg744cf192011-11-08 20:40:14 +02004327 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004328
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004329 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004330}
4331
Johan Hedberg229ab392013-03-15 17:06:53 -05004332static void powered_complete(struct hci_dev *hdev, u8 status)
4333{
4334 struct cmd_lookup match = { NULL, hdev };
4335
4336 BT_DBG("status 0x%02x", status);
4337
4338 hci_dev_lock(hdev);
4339
4340 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4341
4342 new_settings(hdev, match.sk);
4343
4344 hci_dev_unlock(hdev);
4345
4346 if (match.sk)
4347 sock_put(match.sk);
4348}
4349
Johan Hedberg70da6242013-03-15 17:06:51 -05004350static int powered_update_hci(struct hci_dev *hdev)
4351{
Johan Hedberg890ea892013-03-15 17:06:52 -05004352 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004353 u8 link_sec;
4354
Johan Hedberg890ea892013-03-15 17:06:52 -05004355 hci_req_init(&req, hdev);
4356
Johan Hedberg70da6242013-03-15 17:06:51 -05004357 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4358 !lmp_host_ssp_capable(hdev)) {
4359 u8 ssp = 1;
4360
Johan Hedberg890ea892013-03-15 17:06:52 -05004361 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004362 }
4363
Johan Hedbergc73eee92013-04-19 18:35:21 +03004364 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4365 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004366 struct hci_cp_write_le_host_supported cp;
4367
4368 cp.le = 1;
4369 cp.simul = lmp_le_br_capable(hdev);
4370
4371 /* Check first if we already have the right
4372 * host state (host features set)
4373 */
4374 if (cp.le != lmp_host_le_capable(hdev) ||
4375 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004376 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4377 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004378 }
4379
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004380 if (lmp_le_capable(hdev)) {
4381 /* Set random address to static address if configured */
4382 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4383 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4384 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004385
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004386 /* Make sure the controller has a good default for
4387 * advertising data. This also applies to the case
4388 * where BR/EDR was toggled during the AUTO_OFF phase.
4389 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004390 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004391 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004392 update_scan_rsp_data(&req);
4393 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004394
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004395 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4396 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004397 }
4398
Johan Hedberg70da6242013-03-15 17:06:51 -05004399 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4400 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004401 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4402 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004403
4404 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004405 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4406 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004407 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004408 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004409 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004410 }
4411
Johan Hedberg229ab392013-03-15 17:06:53 -05004412 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004413}
4414
Johan Hedberg744cf192011-11-08 20:40:14 +02004415int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004416{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004417 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004418 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4419 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004420 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004421
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004422 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4423 return 0;
4424
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004425 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004426 if (powered_update_hci(hdev) == 0)
4427 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004428
Johan Hedberg229ab392013-03-15 17:06:53 -05004429 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4430 &match);
4431 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004432 }
4433
Johan Hedberg229ab392013-03-15 17:06:53 -05004434 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4435 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4436
4437 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4438 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4439 zero_cod, sizeof(zero_cod), NULL);
4440
4441new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004442 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004443
4444 if (match.sk)
4445 sock_put(match.sk);
4446
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004447 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004448}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004449
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004450void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004451{
4452 struct pending_cmd *cmd;
4453 u8 status;
4454
4455 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4456 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004457 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004458
4459 if (err == -ERFKILL)
4460 status = MGMT_STATUS_RFKILLED;
4461 else
4462 status = MGMT_STATUS_FAILED;
4463
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004464 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004465
4466 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004467}
4468
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004469void mgmt_discoverable_timeout(struct hci_dev *hdev)
4470{
4471 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004472
4473 hci_dev_lock(hdev);
4474
4475 /* When discoverable timeout triggers, then just make sure
4476 * the limited discoverable flag is cleared. Even in the case
4477 * of a timeout triggered from general discoverable, it is
4478 * safe to unconditionally clear the flag.
4479 */
4480 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004481 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004482
4483 hci_req_init(&req, hdev);
Johan Hedberg4b580612013-10-19 23:38:21 +03004484 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4485 u8 scan = SCAN_PAGE;
4486 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
4487 sizeof(scan), &scan);
4488 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004489 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004490 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004491 hci_req_run(&req, NULL);
4492
4493 hdev->discov_timeout = 0;
4494
Johan Hedberg9a43e252013-10-20 19:00:07 +03004495 new_settings(hdev, NULL);
4496
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004497 hci_dev_unlock(hdev);
4498}
4499
Marcel Holtmann86a75642013-10-15 06:33:54 -07004500void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004501{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004502 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004503
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004504 /* Nothing needed here if there's a pending command since that
4505 * commands request completion callback takes care of everything
4506 * necessary.
4507 */
4508 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004509 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004510
Johan Hedberg9a43e252013-10-20 19:00:07 +03004511 if (discoverable) {
Marcel Holtmann86a75642013-10-15 06:33:54 -07004512 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004513 } else {
4514 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmann86a75642013-10-15 06:33:54 -07004515 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004516 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004517
Johan Hedberg9a43e252013-10-20 19:00:07 +03004518 if (changed) {
4519 struct hci_request req;
4520
4521 /* In case this change in discoverable was triggered by
4522 * a disabling of connectable there could be a need to
4523 * update the advertising flags.
4524 */
4525 hci_req_init(&req, hdev);
4526 update_adv_data(&req);
4527 hci_req_run(&req, NULL);
4528
Marcel Holtmann86a75642013-10-15 06:33:54 -07004529 new_settings(hdev, NULL);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004530 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004531}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004532
Marcel Holtmanna3309162013-10-15 06:33:55 -07004533void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004534{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004535 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004536
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004537 /* Nothing needed here if there's a pending command since that
4538 * commands request completion callback takes care of everything
4539 * necessary.
4540 */
4541 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004542 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004543
Marcel Holtmanna3309162013-10-15 06:33:55 -07004544 if (connectable)
4545 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4546 else
4547 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004548
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004549 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004550 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004551}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004552
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004553void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004554{
Johan Hedbergca69b792011-11-11 18:10:00 +02004555 u8 mgmt_err = mgmt_status(status);
4556
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004557 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004558 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004559 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004560
4561 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004562 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004563 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004564}
4565
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004566void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4567 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004568{
Johan Hedberg86742e12011-11-07 23:13:38 +02004569 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004570
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004571 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004572
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004573 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004574 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004575 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004576 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004577 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004578 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004579
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004580 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004581}
Johan Hedbergf7520542011-01-20 12:34:39 +02004582
Marcel Holtmann083368f2013-10-15 14:26:29 -07004583void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004584{
4585 struct mgmt_ev_new_long_term_key ev;
4586
4587 memset(&ev, 0, sizeof(ev));
4588
4589 ev.store_hint = persistent;
4590 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004591 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004592 ev.key.authenticated = key->authenticated;
4593 ev.key.enc_size = key->enc_size;
4594 ev.key.ediv = key->ediv;
4595
4596 if (key->type == HCI_SMP_LTK)
4597 ev.key.master = 1;
4598
4599 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4600 memcpy(ev.key.val, key->val, sizeof(key->val));
4601
Marcel Holtmann083368f2013-10-15 14:26:29 -07004602 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004603}
4604
Marcel Holtmann94933992013-10-15 10:26:39 -07004605static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4606 u8 data_len)
4607{
4608 eir[eir_len++] = sizeof(type) + data_len;
4609 eir[eir_len++] = type;
4610 memcpy(&eir[eir_len], data, data_len);
4611 eir_len += data_len;
4612
4613 return eir_len;
4614}
4615
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004616void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4617 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4618 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004619{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004620 char buf[512];
4621 struct mgmt_ev_device_connected *ev = (void *) buf;
4622 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004623
Johan Hedbergb644ba32012-01-17 21:48:47 +02004624 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004625 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004626
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004627 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004628
Johan Hedbergb644ba32012-01-17 21:48:47 +02004629 if (name_len > 0)
4630 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004631 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004632
4633 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004634 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004635 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004636
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004637 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004638
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004639 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4640 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004641}
4642
Johan Hedberg8962ee72011-01-20 12:40:27 +02004643static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4644{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004645 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004646 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004647 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004648
Johan Hedberg88c3df12012-02-09 14:27:38 +02004649 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4650 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004651
Johan Hedbergaee9b212012-02-18 15:07:59 +02004652 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004653 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004654
4655 *sk = cmd->sk;
4656 sock_hold(*sk);
4657
Johan Hedberga664b5b2011-02-19 12:06:02 -03004658 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004659}
4660
Johan Hedberg124f6e32012-02-09 13:50:12 +02004661static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004662{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004663 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004664 struct mgmt_cp_unpair_device *cp = cmd->param;
4665 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004666
4667 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004668 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4669 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004670
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004671 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4672
Johan Hedbergaee9b212012-02-18 15:07:59 +02004673 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004674
4675 mgmt_pending_remove(cmd);
4676}
4677
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004678void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4679 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004680{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004681 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004682 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004683
Andre Guedes57eb7762013-10-30 19:01:41 -03004684 if (link_type != ACL_LINK && link_type != LE_LINK)
4685 return;
4686
Johan Hedberg744cf192011-11-08 20:40:14 +02004687 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004688
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004689 bacpy(&ev.addr.bdaddr, bdaddr);
4690 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4691 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004692
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004693 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004694
4695 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004696 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004697
Johan Hedberg124f6e32012-02-09 13:50:12 +02004698 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004699 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004700}
4701
Marcel Holtmann78929242013-10-06 23:55:47 -07004702void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4703 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004704{
Andre Guedes3655bba2013-10-30 19:01:40 -03004705 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
4706 struct mgmt_cp_disconnect *cp;
Johan Hedberg88c3df12012-02-09 14:27:38 +02004707 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004708 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004709
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004710 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4711 hdev);
4712
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004713 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004714 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004715 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004716
Andre Guedes3655bba2013-10-30 19:01:40 -03004717 cp = cmd->param;
4718
4719 if (bacmp(bdaddr, &cp->addr.bdaddr))
4720 return;
4721
4722 if (cp->addr.type != bdaddr_type)
4723 return;
4724
Johan Hedberg88c3df12012-02-09 14:27:38 +02004725 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes3655bba2013-10-30 19:01:40 -03004726 rp.addr.type = bdaddr_type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004727
Marcel Holtmann78929242013-10-06 23:55:47 -07004728 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4729 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004730
Johan Hedberga664b5b2011-02-19 12:06:02 -03004731 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004732}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004733
Marcel Holtmann445608d2013-10-06 23:55:48 -07004734void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4735 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004736{
4737 struct mgmt_ev_connect_failed ev;
4738
Johan Hedberg4c659c32011-11-07 23:13:39 +02004739 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004740 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004741 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004742
Marcel Holtmann445608d2013-10-06 23:55:48 -07004743 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004744}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004745
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004746void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004747{
4748 struct mgmt_ev_pin_code_request ev;
4749
Johan Hedbergd8457692012-02-17 14:24:57 +02004750 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004751 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004752 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004753
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004754 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004755}
4756
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004757void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4758 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004759{
4760 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004761 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004762
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004763 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004764 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004765 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004766
Johan Hedbergd8457692012-02-17 14:24:57 +02004767 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004768 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004769
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004770 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
4771 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004772
Johan Hedberga664b5b2011-02-19 12:06:02 -03004773 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004774}
4775
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004776void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4777 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004778{
4779 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004780 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004781
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004782 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004783 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004784 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004785
Johan Hedbergd8457692012-02-17 14:24:57 +02004786 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004787 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004788
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004789 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
4790 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004791
Johan Hedberga664b5b2011-02-19 12:06:02 -03004792 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004793}
Johan Hedberga5c29682011-02-19 12:05:57 -03004794
Johan Hedberg744cf192011-11-08 20:40:14 +02004795int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004796 u8 link_type, u8 addr_type, __le32 value,
4797 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004798{
4799 struct mgmt_ev_user_confirm_request ev;
4800
Johan Hedberg744cf192011-11-08 20:40:14 +02004801 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004802
Johan Hedberg272d90d2012-02-09 15:26:12 +02004803 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004804 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004805 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004806 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004807
Johan Hedberg744cf192011-11-08 20:40:14 +02004808 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004809 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004810}
4811
Johan Hedberg272d90d2012-02-09 15:26:12 +02004812int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004813 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004814{
4815 struct mgmt_ev_user_passkey_request ev;
4816
4817 BT_DBG("%s", hdev->name);
4818
Johan Hedberg272d90d2012-02-09 15:26:12 +02004819 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004820 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004821
4822 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004823 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004824}
4825
Brian Gix0df4c182011-11-16 13:53:13 -08004826static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004827 u8 link_type, u8 addr_type, u8 status,
4828 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004829{
4830 struct pending_cmd *cmd;
4831 struct mgmt_rp_user_confirm_reply rp;
4832 int err;
4833
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004834 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004835 if (!cmd)
4836 return -ENOENT;
4837
Johan Hedberg272d90d2012-02-09 15:26:12 +02004838 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004839 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004840 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004841 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004842
Johan Hedberga664b5b2011-02-19 12:06:02 -03004843 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004844
4845 return err;
4846}
4847
Johan Hedberg744cf192011-11-08 20:40:14 +02004848int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004849 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004850{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004851 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004852 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004853}
4854
Johan Hedberg272d90d2012-02-09 15:26:12 +02004855int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004856 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004857{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004858 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004859 status,
4860 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004861}
Johan Hedberg2a611692011-02-19 12:06:00 -03004862
Brian Gix604086b2011-11-23 08:28:33 -08004863int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004864 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004865{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004866 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004867 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004868}
4869
Johan Hedberg272d90d2012-02-09 15:26:12 +02004870int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004871 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004872{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004873 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004874 status,
4875 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004876}
4877
Johan Hedberg92a25252012-09-06 18:39:26 +03004878int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4879 u8 link_type, u8 addr_type, u32 passkey,
4880 u8 entered)
4881{
4882 struct mgmt_ev_passkey_notify ev;
4883
4884 BT_DBG("%s", hdev->name);
4885
4886 bacpy(&ev.addr.bdaddr, bdaddr);
4887 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4888 ev.passkey = __cpu_to_le32(passkey);
4889 ev.entered = entered;
4890
4891 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4892}
4893
Marcel Holtmanne5460992013-10-15 14:26:23 -07004894void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4895 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004896{
4897 struct mgmt_ev_auth_failed ev;
4898
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004899 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004900 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004901 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004902
Marcel Holtmanne5460992013-10-15 14:26:23 -07004903 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004904}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004905
Marcel Holtmann464996a2013-10-15 14:26:24 -07004906void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004907{
4908 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07004909 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004910
4911 if (status) {
4912 u8 mgmt_err = mgmt_status(status);
4913 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004914 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07004915 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004916 }
4917
Marcel Holtmann464996a2013-10-15 14:26:24 -07004918 if (test_bit(HCI_AUTH, &hdev->flags))
4919 changed = !test_and_set_bit(HCI_LINK_SECURITY,
4920 &hdev->dev_flags);
4921 else
4922 changed = test_and_clear_bit(HCI_LINK_SECURITY,
4923 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02004924
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004925 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004926 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004927
Johan Hedberg47990ea2012-02-22 11:58:37 +02004928 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07004929 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004930
4931 if (match.sk)
4932 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004933}
4934
Johan Hedberg890ea892013-03-15 17:06:52 -05004935static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004936{
Johan Hedberg890ea892013-03-15 17:06:52 -05004937 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004938 struct hci_cp_write_eir cp;
4939
Johan Hedberg976eb202012-10-24 21:12:01 +03004940 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004941 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004942
Johan Hedbergc80da272012-02-22 15:38:48 +02004943 memset(hdev->eir, 0, sizeof(hdev->eir));
4944
Johan Hedbergcacaf522012-02-21 00:52:42 +02004945 memset(&cp, 0, sizeof(cp));
4946
Johan Hedberg890ea892013-03-15 17:06:52 -05004947 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004948}
4949
Marcel Holtmann3e248562013-10-15 14:26:25 -07004950void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004951{
4952 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004953 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004954 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004955
4956 if (status) {
4957 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004958
4959 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004960 &hdev->dev_flags)) {
4961 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004962 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004963 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004964
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004965 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4966 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004967 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004968 }
4969
4970 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004971 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004972 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004973 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4974 if (!changed)
4975 changed = test_and_clear_bit(HCI_HS_ENABLED,
4976 &hdev->dev_flags);
4977 else
4978 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004979 }
4980
4981 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4982
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004983 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07004984 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004985
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004986 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004987 sock_put(match.sk);
4988
Johan Hedberg890ea892013-03-15 17:06:52 -05004989 hci_req_init(&req, hdev);
4990
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004991 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004992 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004993 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004994 clear_eir(&req);
4995
4996 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004997}
4998
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004999void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
5000{
5001 struct cmd_lookup match = { NULL, hdev };
5002 bool changed = false;
5003
5004 if (status) {
5005 u8 mgmt_err = mgmt_status(status);
5006
5007 if (enable && test_and_clear_bit(HCI_SC_ENABLED,
5008 &hdev->dev_flags))
5009 new_settings(hdev, NULL);
5010
5011 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5012 cmd_status_rsp, &mgmt_err);
5013 return;
5014 }
5015
5016 if (enable)
5017 changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
5018 else
5019 changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
5020
5021 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5022 settings_rsp, &match);
5023
5024 if (changed)
5025 new_settings(hdev, match.sk);
5026
5027 if (match.sk)
5028 sock_put(match.sk);
5029}
5030
Johan Hedberg92da6092013-03-15 17:06:55 -05005031static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02005032{
5033 struct cmd_lookup *match = data;
5034
Johan Hedberg90e70452012-02-23 23:09:40 +02005035 if (match->sk == NULL) {
5036 match->sk = cmd->sk;
5037 sock_hold(match->sk);
5038 }
Johan Hedberg90e70452012-02-23 23:09:40 +02005039}
5040
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005041void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
5042 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005043{
Johan Hedberg90e70452012-02-23 23:09:40 +02005044 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005045
Johan Hedberg92da6092013-03-15 17:06:55 -05005046 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
5047 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
5048 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02005049
5050 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005051 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
5052 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02005053
5054 if (match.sk)
5055 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005056}
5057
Marcel Holtmann7667da32013-10-15 14:26:27 -07005058void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02005059{
Johan Hedbergb312b1612011-03-16 14:29:37 +02005060 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05005061 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005062
Johan Hedberg13928972013-03-15 17:07:00 -05005063 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07005064 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005065
5066 memset(&ev, 0, sizeof(ev));
5067 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005068 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005069
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005070 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05005071 if (!cmd) {
5072 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02005073
Johan Hedberg13928972013-03-15 17:07:00 -05005074 /* If this is a HCI command related to powering on the
5075 * HCI dev don't send any mgmt signals.
5076 */
5077 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07005078 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005079 }
5080
Marcel Holtmann7667da32013-10-15 14:26:27 -07005081 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
5082 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005083}
Szymon Jancc35938b2011-03-22 13:12:21 +01005084
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005085void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
5086 u8 *randomizer192, u8 *hash256,
5087 u8 *randomizer256, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01005088{
5089 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01005090
Johan Hedberg744cf192011-11-08 20:40:14 +02005091 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01005092
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005093 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01005094 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005095 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01005096
5097 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005098 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
5099 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01005100 } else {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005101 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
5102 hash256 && randomizer256) {
5103 struct mgmt_rp_read_local_oob_ext_data rp;
Szymon Jancc35938b2011-03-22 13:12:21 +01005104
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005105 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
5106 memcpy(rp.randomizer192, randomizer192,
5107 sizeof(rp.randomizer192));
Szymon Jancc35938b2011-03-22 13:12:21 +01005108
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005109 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
5110 memcpy(rp.randomizer256, randomizer256,
5111 sizeof(rp.randomizer256));
5112
5113 cmd_complete(cmd->sk, hdev->id,
5114 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5115 &rp, sizeof(rp));
5116 } else {
5117 struct mgmt_rp_read_local_oob_data rp;
5118
5119 memcpy(rp.hash, hash192, sizeof(rp.hash));
5120 memcpy(rp.randomizer, randomizer192,
5121 sizeof(rp.randomizer));
5122
5123 cmd_complete(cmd->sk, hdev->id,
5124 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5125 &rp, sizeof(rp));
5126 }
Szymon Jancc35938b2011-03-22 13:12:21 +01005127 }
5128
5129 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01005130}
Johan Hedberge17acd42011-03-30 23:57:16 +03005131
Marcel Holtmann901801b2013-10-06 23:55:51 -07005132void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5133 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
5134 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03005135{
Johan Hedberge319d2e2012-01-15 19:51:59 +02005136 char buf[512];
5137 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02005138 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03005139
Andre Guedes12602d02013-04-30 15:29:40 -03005140 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005141 return;
Andre Guedes12602d02013-04-30 15:29:40 -03005142
Johan Hedberg1dc06092012-01-15 21:01:23 +02005143 /* Leave 5 bytes for a potential CoD field */
5144 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005145 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03005146
Johan Hedberg1dc06092012-01-15 21:01:23 +02005147 memset(buf, 0, sizeof(buf));
5148
Johan Hedberge319d2e2012-01-15 19:51:59 +02005149 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005150 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02005151 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02005152 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305153 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02005154 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305155 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03005156
Johan Hedberg1dc06092012-01-15 21:01:23 +02005157 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02005158 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03005159
Johan Hedberg1dc06092012-01-15 21:01:23 +02005160 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
5161 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005162 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005163
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005164 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005165 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03005166
Marcel Holtmann901801b2013-10-06 23:55:51 -07005167 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03005168}
Johan Hedberga88a9652011-03-30 13:18:12 +03005169
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005170void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5171 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03005172{
Johan Hedbergb644ba32012-01-17 21:48:47 +02005173 struct mgmt_ev_device_found *ev;
5174 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
5175 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03005176
Johan Hedbergb644ba32012-01-17 21:48:47 +02005177 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03005178
Johan Hedbergb644ba32012-01-17 21:48:47 +02005179 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03005180
Johan Hedbergb644ba32012-01-17 21:48:47 +02005181 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005182 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005183 ev->rssi = rssi;
5184
5185 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005186 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005187
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005188 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005189
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005190 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03005191}
Johan Hedberg314b2382011-04-27 10:29:57 -04005192
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005193void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04005194{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005195 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02005196 struct pending_cmd *cmd;
5197
Andre Guedes343fb142011-11-22 17:14:19 -03005198 BT_DBG("%s discovering %u", hdev->name, discovering);
5199
Johan Hedberg164a6e72011-11-01 17:06:44 +02005200 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005201 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005202 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005203 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005204
5205 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02005206 u8 type = hdev->discovery.type;
5207
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005208 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
5209 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02005210 mgmt_pending_remove(cmd);
5211 }
5212
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005213 memset(&ev, 0, sizeof(ev));
5214 ev.type = hdev->discovery.type;
5215 ev.discovering = discovering;
5216
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005217 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04005218}
Antti Julku5e762442011-08-25 16:48:02 +03005219
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005220int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005221{
5222 struct pending_cmd *cmd;
5223 struct mgmt_ev_device_blocked ev;
5224
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005225 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005226
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005227 bacpy(&ev.addr.bdaddr, bdaddr);
5228 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005229
Johan Hedberg744cf192011-11-08 20:40:14 +02005230 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005231 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005232}
5233
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005234int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005235{
5236 struct pending_cmd *cmd;
5237 struct mgmt_ev_device_unblocked ev;
5238
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005239 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005240
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005241 bacpy(&ev.addr.bdaddr, bdaddr);
5242 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005243
Johan Hedberg744cf192011-11-08 20:40:14 +02005244 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005245 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005246}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005247
5248static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5249{
5250 BT_DBG("%s status %u", hdev->name, status);
5251
5252 /* Clear the advertising mgmt setting if we failed to re-enable it */
5253 if (status) {
5254 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005255 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005256 }
5257}
5258
5259void mgmt_reenable_advertising(struct hci_dev *hdev)
5260{
5261 struct hci_request req;
5262
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005263 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005264 return;
5265
5266 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5267 return;
5268
5269 hci_req_init(&req, hdev);
5270 enable_advertising(&req);
5271
5272 /* If this fails we have no option but to let user space know
5273 * that we've disabled advertising.
5274 */
5275 if (hci_req_run(&req, adv_enable_complete) < 0) {
5276 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005277 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005278 }
5279}