blob: 48aa23977da340e8f5109b26bf73f12f1b8989a3 [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,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020082};
83
84static const u16 mgmt_events[] = {
85 MGMT_EV_CONTROLLER_ERROR,
86 MGMT_EV_INDEX_ADDED,
87 MGMT_EV_INDEX_REMOVED,
88 MGMT_EV_NEW_SETTINGS,
89 MGMT_EV_CLASS_OF_DEV_CHANGED,
90 MGMT_EV_LOCAL_NAME_CHANGED,
91 MGMT_EV_NEW_LINK_KEY,
92 MGMT_EV_NEW_LONG_TERM_KEY,
93 MGMT_EV_DEVICE_CONNECTED,
94 MGMT_EV_DEVICE_DISCONNECTED,
95 MGMT_EV_CONNECT_FAILED,
96 MGMT_EV_PIN_CODE_REQUEST,
97 MGMT_EV_USER_CONFIRM_REQUEST,
98 MGMT_EV_USER_PASSKEY_REQUEST,
99 MGMT_EV_AUTH_FAILED,
100 MGMT_EV_DEVICE_FOUND,
101 MGMT_EV_DISCOVERING,
102 MGMT_EV_DEVICE_BLOCKED,
103 MGMT_EV_DEVICE_UNBLOCKED,
104 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300105 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200106};
107
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800108#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200109
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200110#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
111 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
112
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200113struct pending_cmd {
114 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200115 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200116 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100117 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200118 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300119 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200120};
121
Johan Hedbergca69b792011-11-11 18:10:00 +0200122/* HCI to MGMT error code conversion table */
123static u8 mgmt_status_table[] = {
124 MGMT_STATUS_SUCCESS,
125 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
126 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
127 MGMT_STATUS_FAILED, /* Hardware Failure */
128 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
129 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
130 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
131 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
132 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
133 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
134 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
135 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
136 MGMT_STATUS_BUSY, /* Command Disallowed */
137 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
138 MGMT_STATUS_REJECTED, /* Rejected Security */
139 MGMT_STATUS_REJECTED, /* Rejected Personal */
140 MGMT_STATUS_TIMEOUT, /* Host Timeout */
141 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
142 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
143 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
144 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
145 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
146 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
147 MGMT_STATUS_BUSY, /* Repeated Attempts */
148 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
149 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
150 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
151 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
152 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
153 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
154 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
155 MGMT_STATUS_FAILED, /* Unspecified Error */
156 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
157 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
158 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
159 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
160 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
161 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
162 MGMT_STATUS_FAILED, /* Unit Link Key Used */
163 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
164 MGMT_STATUS_TIMEOUT, /* Instant Passed */
165 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
166 MGMT_STATUS_FAILED, /* Transaction Collision */
167 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
168 MGMT_STATUS_REJECTED, /* QoS Rejected */
169 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
170 MGMT_STATUS_REJECTED, /* Insufficient Security */
171 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
172 MGMT_STATUS_BUSY, /* Role Switch Pending */
173 MGMT_STATUS_FAILED, /* Slot Violation */
174 MGMT_STATUS_FAILED, /* Role Switch Failed */
175 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
176 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
177 MGMT_STATUS_BUSY, /* Host Busy Pairing */
178 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
179 MGMT_STATUS_BUSY, /* Controller Busy */
180 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
181 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
182 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
183 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
184 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
185};
186
187static u8 mgmt_status(u8 hci_status)
188{
189 if (hci_status < ARRAY_SIZE(mgmt_status_table))
190 return mgmt_status_table[hci_status];
191
192 return MGMT_STATUS_FAILED;
193}
194
Szymon Janc4e51eae2011-02-25 19:05:48 +0100195static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200196{
197 struct sk_buff *skb;
198 struct mgmt_hdr *hdr;
199 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300200 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200201
Szymon Janc34eb5252011-02-28 14:10:08 +0100202 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200203
Andre Guedes790eff42012-06-07 19:05:46 -0300204 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200205 if (!skb)
206 return -ENOMEM;
207
208 hdr = (void *) skb_put(skb, sizeof(*hdr));
209
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530210 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100211 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200212 hdr->len = cpu_to_le16(sizeof(*ev));
213
214 ev = (void *) skb_put(skb, sizeof(*ev));
215 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200216 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200217
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300218 err = sock_queue_rcv_skb(sk, skb);
219 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200220 kfree_skb(skb);
221
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300222 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223}
224
Johan Hedbergaee9b212012-02-18 15:07:59 +0200225static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300226 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200227{
228 struct sk_buff *skb;
229 struct mgmt_hdr *hdr;
230 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300231 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200232
233 BT_DBG("sock %p", sk);
234
Andre Guedes790eff42012-06-07 19:05:46 -0300235 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200236 if (!skb)
237 return -ENOMEM;
238
239 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200240
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530241 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100242 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200243 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200244
Johan Hedberga38528f2011-01-22 06:46:43 +0200245 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200246 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200247 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100248
249 if (rp)
250 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200251
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300252 err = sock_queue_rcv_skb(sk, skb);
253 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200254 kfree_skb(skb);
255
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100256 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200257}
258
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300259static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
260 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200261{
262 struct mgmt_rp_read_version rp;
263
264 BT_DBG("sock %p", sk);
265
266 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200267 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200268
Johan Hedbergaee9b212012-02-18 15:07:59 +0200269 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300270 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200271}
272
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300273static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
274 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200275{
276 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200277 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
278 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200279 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200280 size_t rp_size;
281 int i, err;
282
283 BT_DBG("sock %p", sk);
284
285 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
286
287 rp = kmalloc(rp_size, GFP_KERNEL);
288 if (!rp)
289 return -ENOMEM;
290
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200291 rp->num_commands = __constant_cpu_to_le16(num_commands);
292 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200293
294 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
295 put_unaligned_le16(mgmt_commands[i], opcode);
296
297 for (i = 0; i < num_events; i++, opcode++)
298 put_unaligned_le16(mgmt_events[i], opcode);
299
Johan Hedbergaee9b212012-02-18 15:07:59 +0200300 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300301 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200302 kfree(rp);
303
304 return err;
305}
306
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300307static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
308 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200309{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200310 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200311 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200312 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300314 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200315
316 BT_DBG("sock %p", sk);
317
318 read_lock(&hci_dev_list_lock);
319
320 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300321 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700322 if (d->dev_type == HCI_BREDR)
323 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324 }
325
Johan Hedberga38528f2011-01-22 06:46:43 +0200326 rp_len = sizeof(*rp) + (2 * count);
327 rp = kmalloc(rp_len, GFP_ATOMIC);
328 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100329 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200330 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100331 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200332
Johan Hedberg476e44c2012-10-19 20:10:46 +0300333 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200334 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200335 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200336 continue;
337
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700338 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
339 continue;
340
Marcel Holtmann1514b892013-10-06 08:25:01 -0700341 if (d->dev_type == HCI_BREDR) {
342 rp->index[count++] = cpu_to_le16(d->id);
343 BT_DBG("Added hci%u", d->id);
344 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200345 }
346
Johan Hedberg476e44c2012-10-19 20:10:46 +0300347 rp->num_controllers = cpu_to_le16(count);
348 rp_len = sizeof(*rp) + (2 * count);
349
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200350 read_unlock(&hci_dev_list_lock);
351
Johan Hedbergaee9b212012-02-18 15:07:59 +0200352 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300353 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354
Johan Hedberga38528f2011-01-22 06:46:43 +0200355 kfree(rp);
356
357 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200358}
359
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200360static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200361{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200363
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200366
Andre Guedesed3fa312012-07-24 15:03:46 -0300367 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300368 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500369 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
370 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300371 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 settings |= MGMT_SETTING_BREDR;
373 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700374
375 if (lmp_ssp_capable(hdev)) {
376 settings |= MGMT_SETTING_SSP;
377 settings |= MGMT_SETTING_HS;
378 }
Marcel Holtmann848566b2013-10-01 22:59:22 -0700379 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300381 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200382 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300383 settings |= MGMT_SETTING_ADVERTISING;
384 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200385
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200386 return settings;
387}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200388
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200389static u32 get_current_settings(struct hci_dev *hdev)
390{
391 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200392
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200393 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100394 settings |= MGMT_SETTING_POWERED;
395
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200396 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200397 settings |= MGMT_SETTING_CONNECTABLE;
398
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500399 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
400 settings |= MGMT_SETTING_FAST_CONNECTABLE;
401
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200402 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403 settings |= MGMT_SETTING_DISCOVERABLE;
404
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200405 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200406 settings |= MGMT_SETTING_PAIRABLE;
407
Johan Hedberg56f87902013-10-02 13:43:13 +0300408 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200409 settings |= MGMT_SETTING_BREDR;
410
Johan Hedberg06199cf2012-02-22 16:37:11 +0200411 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200412 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200413
Johan Hedberg47990ea2012-02-22 11:58:37 +0200414 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200416
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200417 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200418 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200419
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200420 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
421 settings |= MGMT_SETTING_HS;
422
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200423 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300424 settings |= MGMT_SETTING_ADVERTISING;
425
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200426 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200427}
428
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300429#define PNP_INFO_SVCLASS_ID 0x1200
430
Johan Hedberg213202e2013-01-27 00:31:33 +0200431static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
432{
433 u8 *ptr = data, *uuids_start = NULL;
434 struct bt_uuid *uuid;
435
436 if (len < 4)
437 return ptr;
438
439 list_for_each_entry(uuid, &hdev->uuids, list) {
440 u16 uuid16;
441
442 if (uuid->size != 16)
443 continue;
444
445 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
446 if (uuid16 < 0x1100)
447 continue;
448
449 if (uuid16 == PNP_INFO_SVCLASS_ID)
450 continue;
451
452 if (!uuids_start) {
453 uuids_start = ptr;
454 uuids_start[0] = 1;
455 uuids_start[1] = EIR_UUID16_ALL;
456 ptr += 2;
457 }
458
459 /* Stop if not enough space to put next UUID */
460 if ((ptr - data) + sizeof(u16) > len) {
461 uuids_start[1] = EIR_UUID16_SOME;
462 break;
463 }
464
465 *ptr++ = (uuid16 & 0x00ff);
466 *ptr++ = (uuid16 & 0xff00) >> 8;
467 uuids_start[0] += sizeof(uuid16);
468 }
469
470 return ptr;
471}
472
Johan Hedbergcdf19632013-01-27 00:31:34 +0200473static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
474{
475 u8 *ptr = data, *uuids_start = NULL;
476 struct bt_uuid *uuid;
477
478 if (len < 6)
479 return ptr;
480
481 list_for_each_entry(uuid, &hdev->uuids, list) {
482 if (uuid->size != 32)
483 continue;
484
485 if (!uuids_start) {
486 uuids_start = ptr;
487 uuids_start[0] = 1;
488 uuids_start[1] = EIR_UUID32_ALL;
489 ptr += 2;
490 }
491
492 /* Stop if not enough space to put next UUID */
493 if ((ptr - data) + sizeof(u32) > len) {
494 uuids_start[1] = EIR_UUID32_SOME;
495 break;
496 }
497
498 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
499 ptr += sizeof(u32);
500 uuids_start[0] += sizeof(u32);
501 }
502
503 return ptr;
504}
505
Johan Hedbergc00d5752013-01-27 00:31:35 +0200506static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
507{
508 u8 *ptr = data, *uuids_start = NULL;
509 struct bt_uuid *uuid;
510
511 if (len < 18)
512 return ptr;
513
514 list_for_each_entry(uuid, &hdev->uuids, list) {
515 if (uuid->size != 128)
516 continue;
517
518 if (!uuids_start) {
519 uuids_start = ptr;
520 uuids_start[0] = 1;
521 uuids_start[1] = EIR_UUID128_ALL;
522 ptr += 2;
523 }
524
525 /* Stop if not enough space to put next UUID */
526 if ((ptr - data) + 16 > len) {
527 uuids_start[1] = EIR_UUID128_SOME;
528 break;
529 }
530
531 memcpy(ptr, uuid->uuid, 16);
532 ptr += 16;
533 uuids_start[0] += 16;
534 }
535
536 return ptr;
537}
538
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300539static void create_eir(struct hci_dev *hdev, u8 *data)
540{
541 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 size_t name_len;
543
544 name_len = strlen(hdev->dev_name);
545
546 if (name_len > 0) {
547 /* EIR Data type */
548 if (name_len > 48) {
549 name_len = 48;
550 ptr[1] = EIR_NAME_SHORT;
551 } else
552 ptr[1] = EIR_NAME_COMPLETE;
553
554 /* EIR Data length */
555 ptr[0] = name_len + 1;
556
557 memcpy(ptr + 2, hdev->dev_name, name_len);
558
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300559 ptr += (name_len + 2);
560 }
561
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100562 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700563 ptr[0] = 2;
564 ptr[1] = EIR_TX_POWER;
565 ptr[2] = (u8) hdev->inq_tx_power;
566
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700567 ptr += 3;
568 }
569
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700570 if (hdev->devid_source > 0) {
571 ptr[0] = 9;
572 ptr[1] = EIR_DEVICE_ID;
573
574 put_unaligned_le16(hdev->devid_source, ptr + 2);
575 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
576 put_unaligned_le16(hdev->devid_product, ptr + 6);
577 put_unaligned_le16(hdev->devid_version, ptr + 8);
578
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700579 ptr += 10;
580 }
581
Johan Hedberg213202e2013-01-27 00:31:33 +0200582 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200583 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200584 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300585}
586
Johan Hedberg890ea892013-03-15 17:06:52 -0500587static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300588{
Johan Hedberg890ea892013-03-15 17:06:52 -0500589 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300590 struct hci_cp_write_eir cp;
591
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200592 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500593 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200594
Johan Hedberg976eb202012-10-24 21:12:01 +0300595 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500596 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300597
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200598 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500599 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300600
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200601 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500602 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300603
604 memset(&cp, 0, sizeof(cp));
605
606 create_eir(hdev, cp.data);
607
608 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500609 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300610
611 memcpy(hdev->eir, cp.data, sizeof(cp.data));
612
Johan Hedberg890ea892013-03-15 17:06:52 -0500613 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300614}
615
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200616static u8 get_service_classes(struct hci_dev *hdev)
617{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300618 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200619 u8 val = 0;
620
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300621 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200622 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200623
624 return val;
625}
626
Johan Hedberg890ea892013-03-15 17:06:52 -0500627static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200628{
Johan Hedberg890ea892013-03-15 17:06:52 -0500629 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200630 u8 cod[3];
631
632 BT_DBG("%s", hdev->name);
633
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200634 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500635 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200636
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200637 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500638 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200639
640 cod[0] = hdev->minor_class;
641 cod[1] = hdev->major_class;
642 cod[2] = get_service_classes(hdev);
643
644 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500645 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200646
Johan Hedberg890ea892013-03-15 17:06:52 -0500647 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200648}
649
Johan Hedberg7d785252011-12-15 00:47:39 +0200650static void service_cache_off(struct work_struct *work)
651{
652 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300653 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500654 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200655
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200656 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200657 return;
658
Johan Hedberg890ea892013-03-15 17:06:52 -0500659 hci_req_init(&req, hdev);
660
Johan Hedberg7d785252011-12-15 00:47:39 +0200661 hci_dev_lock(hdev);
662
Johan Hedberg890ea892013-03-15 17:06:52 -0500663 update_eir(&req);
664 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200665
666 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500667
668 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200669}
670
Johan Hedberg6a919082012-02-28 06:17:26 +0200671static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200672{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200673 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200674 return;
675
Johan Hedberg4f87da82012-03-02 19:55:56 +0200676 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200677
Johan Hedberg4f87da82012-03-02 19:55:56 +0200678 /* Non-mgmt controlled devices get this bit set
679 * implicitly so that pairing works for them, however
680 * for mgmt we require user-space to explicitly enable
681 * it
682 */
683 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200684}
685
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200686static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300687 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200688{
689 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200690
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200691 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200692
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300693 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200694
Johan Hedberg03811012010-12-08 00:21:06 +0200695 memset(&rp, 0, sizeof(rp));
696
Johan Hedberg03811012010-12-08 00:21:06 +0200697 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200698
699 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200700 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200701
702 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
703 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
704
705 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200706
707 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200708 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200709
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300710 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200711
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200712 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300713 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200714}
715
716static void mgmt_pending_free(struct pending_cmd *cmd)
717{
718 sock_put(cmd->sk);
719 kfree(cmd->param);
720 kfree(cmd);
721}
722
723static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300724 struct hci_dev *hdev, void *data,
725 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200726{
727 struct pending_cmd *cmd;
728
Andre Guedes12b94562012-06-07 19:05:45 -0300729 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200730 if (!cmd)
731 return NULL;
732
733 cmd->opcode = opcode;
734 cmd->index = hdev->id;
735
Andre Guedes12b94562012-06-07 19:05:45 -0300736 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200737 if (!cmd->param) {
738 kfree(cmd);
739 return NULL;
740 }
741
742 if (data)
743 memcpy(cmd->param, data, len);
744
745 cmd->sk = sk;
746 sock_hold(sk);
747
748 list_add(&cmd->list, &hdev->mgmt_pending);
749
750 return cmd;
751}
752
753static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300754 void (*cb)(struct pending_cmd *cmd,
755 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300756 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200757{
Andre Guedesa3d09352013-02-01 11:21:30 -0300758 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200759
Andre Guedesa3d09352013-02-01 11:21:30 -0300760 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200761 if (opcode > 0 && cmd->opcode != opcode)
762 continue;
763
764 cb(cmd, data);
765 }
766}
767
768static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
769{
770 struct pending_cmd *cmd;
771
772 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
773 if (cmd->opcode == opcode)
774 return cmd;
775 }
776
777 return NULL;
778}
779
780static void mgmt_pending_remove(struct pending_cmd *cmd)
781{
782 list_del(&cmd->list);
783 mgmt_pending_free(cmd);
784}
785
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200786static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200787{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200788 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200789
Johan Hedbergaee9b212012-02-18 15:07:59 +0200790 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300791 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200792}
793
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200794static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300795 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200796{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300797 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200798 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200799 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200800
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200801 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200802
Johan Hedberga7e80f22013-01-09 16:05:19 +0200803 if (cp->val != 0x00 && cp->val != 0x01)
804 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
805 MGMT_STATUS_INVALID_PARAMS);
806
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300807 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200808
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300809 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
810 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
811 MGMT_STATUS_BUSY);
812 goto failed;
813 }
814
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100815 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
816 cancel_delayed_work(&hdev->power_off);
817
818 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200819 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
820 data, len);
821 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100822 goto failed;
823 }
824 }
825
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200826 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200827 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200828 goto failed;
829 }
830
Johan Hedberg03811012010-12-08 00:21:06 +0200831 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
832 if (!cmd) {
833 err = -ENOMEM;
834 goto failed;
835 }
836
837 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200838 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200839 else
Johan Hedberg19202572013-01-14 22:33:51 +0200840 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200841
842 err = 0;
843
844failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300845 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200846 return err;
847}
848
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300849static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
850 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200851{
852 struct sk_buff *skb;
853 struct mgmt_hdr *hdr;
854
Andre Guedes790eff42012-06-07 19:05:46 -0300855 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200856 if (!skb)
857 return -ENOMEM;
858
859 hdr = (void *) skb_put(skb, sizeof(*hdr));
860 hdr->opcode = cpu_to_le16(event);
861 if (hdev)
862 hdr->index = cpu_to_le16(hdev->id);
863 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530864 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200865 hdr->len = cpu_to_le16(data_len);
866
867 if (data)
868 memcpy(skb_put(skb, data_len), data, data_len);
869
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100870 /* Time stamp */
871 __net_timestamp(skb);
872
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200873 hci_send_to_control(skb, skip_sk);
874 kfree_skb(skb);
875
876 return 0;
877}
878
879static int new_settings(struct hci_dev *hdev, struct sock *skip)
880{
881 __le32 ev;
882
883 ev = cpu_to_le32(get_current_settings(hdev));
884
885 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
886}
887
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300888struct cmd_lookup {
889 struct sock *sk;
890 struct hci_dev *hdev;
891 u8 mgmt_status;
892};
893
894static void settings_rsp(struct pending_cmd *cmd, void *data)
895{
896 struct cmd_lookup *match = data;
897
898 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
899
900 list_del(&cmd->list);
901
902 if (match->sk == NULL) {
903 match->sk = cmd->sk;
904 sock_hold(match->sk);
905 }
906
907 mgmt_pending_free(cmd);
908}
909
910static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
911{
912 u8 *status = data;
913
914 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
915 mgmt_pending_remove(cmd);
916}
917
Johan Hedberge6fe7982013-10-02 15:45:22 +0300918static u8 mgmt_bredr_support(struct hci_dev *hdev)
919{
920 if (!lmp_bredr_capable(hdev))
921 return MGMT_STATUS_NOT_SUPPORTED;
922 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
923 return MGMT_STATUS_REJECTED;
924 else
925 return MGMT_STATUS_SUCCESS;
926}
927
928static u8 mgmt_le_support(struct hci_dev *hdev)
929{
930 if (!lmp_le_capable(hdev))
931 return MGMT_STATUS_NOT_SUPPORTED;
932 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
933 return MGMT_STATUS_REJECTED;
934 else
935 return MGMT_STATUS_SUCCESS;
936}
937
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200938static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300939 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200940{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300941 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200942 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200943 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +0300944 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +0200945 int err;
946
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200947 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200948
Johan Hedberge6fe7982013-10-02 15:45:22 +0300949 status = mgmt_bredr_support(hdev);
950 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +0300951 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +0300952 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +0300953
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_DISCOVERABLE,
956 MGMT_STATUS_INVALID_PARAMS);
957
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700958 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100959 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200960 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300961 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200962
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300963 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200964
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200965 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200966 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300967 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200968 goto failed;
969 }
970
971 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300972 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200973 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300974 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200975 goto failed;
976 }
977
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200978 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200979 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300980 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200981 goto failed;
982 }
983
984 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200985 bool changed = false;
986
987 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
988 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
989 changed = true;
990 }
991
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200992 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200993 if (err < 0)
994 goto failed;
995
996 if (changed)
997 err = new_settings(hdev, sk);
998
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200999 goto failed;
1000 }
1001
1002 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +01001003 if (hdev->discov_timeout > 0) {
1004 cancel_delayed_work(&hdev->discov_off);
1005 hdev->discov_timeout = 0;
1006 }
1007
1008 if (cp->val && timeout > 0) {
1009 hdev->discov_timeout = timeout;
1010 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1011 msecs_to_jiffies(hdev->discov_timeout * 1000));
1012 }
1013
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001014 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001015 goto failed;
1016 }
1017
1018 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1019 if (!cmd) {
1020 err = -ENOMEM;
1021 goto failed;
1022 }
1023
1024 scan = SCAN_PAGE;
1025
1026 if (cp->val)
1027 scan |= SCAN_INQUIRY;
1028 else
1029 cancel_delayed_work(&hdev->discov_off);
1030
1031 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1032 if (err < 0)
1033 mgmt_pending_remove(cmd);
1034
Johan Hedberg03811012010-12-08 00:21:06 +02001035 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001036 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001037
1038failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001039 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001040 return err;
1041}
1042
Johan Hedberg406d7802013-03-15 17:07:09 -05001043static void write_fast_connectable(struct hci_request *req, bool enable)
1044{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001045 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001046 struct hci_cp_write_page_scan_activity acp;
1047 u8 type;
1048
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001049 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1050 return;
1051
Johan Hedberg406d7802013-03-15 17:07:09 -05001052 if (enable) {
1053 type = PAGE_SCAN_TYPE_INTERLACED;
1054
1055 /* 160 msec page scan interval */
1056 acp.interval = __constant_cpu_to_le16(0x0100);
1057 } else {
1058 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1059
1060 /* default 1.28 sec page scan */
1061 acp.interval = __constant_cpu_to_le16(0x0800);
1062 }
1063
1064 acp.window = __constant_cpu_to_le16(0x0012);
1065
Johan Hedbergbd98b992013-03-15 17:07:13 -05001066 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1067 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1068 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1069 sizeof(acp), &acp);
1070
1071 if (hdev->page_scan_type != type)
1072 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001073}
1074
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001075static u8 get_adv_type(struct hci_dev *hdev)
1076{
1077 struct pending_cmd *cmd;
1078 bool connectable;
1079
1080 /* If there's a pending mgmt command the flag will not yet have
1081 * it's final value, so check for this first.
1082 */
1083 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1084 if (cmd) {
1085 struct mgmt_mode *cp = cmd->param;
1086 connectable = !!cp->val;
1087 } else {
1088 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1089 }
1090
1091 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1092}
1093
Johan Hedberg95c66e72013-10-14 16:20:06 +03001094static void enable_advertising(struct hci_request *req)
1095{
1096 struct hci_dev *hdev = req->hdev;
1097 struct hci_cp_le_set_adv_param cp;
1098 u8 enable = 0x01;
1099
1100 memset(&cp, 0, sizeof(cp));
1101 cp.min_interval = __constant_cpu_to_le16(0x0800);
1102 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001103 cp.type = get_adv_type(hdev);
Johan Hedberg95c66e72013-10-14 16:20:06 +03001104 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1105 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1106 else
1107 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1108 cp.channel_map = 0x07;
1109
1110 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1111
1112 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1113}
1114
1115static void disable_advertising(struct hci_request *req)
1116{
1117 u8 enable = 0x00;
1118
1119 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1120}
1121
Johan Hedberg2b76f452013-03-15 17:07:04 -05001122static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1123{
1124 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001125 struct mgmt_mode *cp;
1126 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001127
1128 BT_DBG("status 0x%02x", status);
1129
1130 hci_dev_lock(hdev);
1131
1132 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1133 if (!cmd)
1134 goto unlock;
1135
Johan Hedberg37438c12013-10-14 16:20:05 +03001136 if (status) {
1137 u8 mgmt_err = mgmt_status(status);
1138 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1139 goto remove_cmd;
1140 }
1141
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001142 cp = cmd->param;
1143 if (cp->val)
1144 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1145 else
1146 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1147
Johan Hedberg2b76f452013-03-15 17:07:04 -05001148 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1149
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001150 if (changed)
1151 new_settings(hdev, cmd->sk);
1152
Johan Hedberg37438c12013-10-14 16:20:05 +03001153remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001154 mgmt_pending_remove(cmd);
1155
1156unlock:
1157 hci_dev_unlock(hdev);
1158}
1159
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001160static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001161 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001162{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001163 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001164 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001165 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001166 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001167 int err;
1168
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001169 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001170
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001171 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1172 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001173 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001174 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001175
Johan Hedberga7e80f22013-01-09 16:05:19 +02001176 if (cp->val != 0x00 && cp->val != 0x01)
1177 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1178 MGMT_STATUS_INVALID_PARAMS);
1179
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001180 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001181
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001182 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001183 bool changed = false;
1184
1185 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1186 changed = true;
1187
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001188 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001189 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001190 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001191 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1192 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1193 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001194
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001195 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001196 if (err < 0)
1197 goto failed;
1198
1199 if (changed)
1200 err = new_settings(hdev, sk);
1201
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001202 goto failed;
1203 }
1204
1205 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001206 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001207 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001208 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001209 goto failed;
1210 }
1211
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001212 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1213 if (!cmd) {
1214 err = -ENOMEM;
1215 goto failed;
1216 }
1217
Johan Hedberg2b76f452013-03-15 17:07:04 -05001218 hci_req_init(&req, hdev);
1219
Johan Hedberg9b742462013-10-14 16:20:03 +03001220 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) &&
1221 cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
1222
1223 if (cp->val) {
1224 scan = SCAN_PAGE;
1225 } else {
1226 scan = 0;
1227
1228 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1229 hdev->discov_timeout > 0)
1230 cancel_delayed_work(&hdev->discov_off);
1231 }
1232
1233 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1234 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001235
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001236 /* If we're going from non-connectable to connectable or
1237 * vice-versa when fast connectable is enabled ensure that fast
1238 * connectable gets disabled. write_fast_connectable won't do
1239 * anything if the page scan parameters are already what they
1240 * should be.
1241 */
1242 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001243 write_fast_connectable(&req, false);
1244
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001245 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1246 hci_conn_num(hdev, LE_LINK) == 0) {
1247 disable_advertising(&req);
1248 enable_advertising(&req);
1249 }
1250
Johan Hedberg2b76f452013-03-15 17:07:04 -05001251 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001252 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001253 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001254 if (err == -ENODATA)
1255 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE,
1256 hdev);
1257 goto failed;
1258 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001259
1260failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001261 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001262 return err;
1263}
1264
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001265static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001266 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001267{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001268 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001269 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001270 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001271
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001272 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001273
Johan Hedberga7e80f22013-01-09 16:05:19 +02001274 if (cp->val != 0x00 && cp->val != 0x01)
1275 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1276 MGMT_STATUS_INVALID_PARAMS);
1277
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001278 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001279
1280 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001281 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001282 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001283 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001284
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001285 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001286 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001287 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001288
Marcel Holtmann55594352013-10-06 16:11:57 -07001289 if (changed)
1290 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001291
Marcel Holtmann55594352013-10-06 16:11:57 -07001292unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001293 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001294 return err;
1295}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001296
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001297static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1298 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001299{
1300 struct mgmt_mode *cp = data;
1301 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001302 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001303 int err;
1304
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001305 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001306
Johan Hedberge6fe7982013-10-02 15:45:22 +03001307 status = mgmt_bredr_support(hdev);
1308 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001309 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001310 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001311
Johan Hedberga7e80f22013-01-09 16:05:19 +02001312 if (cp->val != 0x00 && cp->val != 0x01)
1313 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1314 MGMT_STATUS_INVALID_PARAMS);
1315
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001316 hci_dev_lock(hdev);
1317
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001318 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001319 bool changed = false;
1320
1321 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001322 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001323 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1324 changed = true;
1325 }
1326
1327 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1328 if (err < 0)
1329 goto failed;
1330
1331 if (changed)
1332 err = new_settings(hdev, sk);
1333
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001334 goto failed;
1335 }
1336
1337 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001338 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001339 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001340 goto failed;
1341 }
1342
1343 val = !!cp->val;
1344
1345 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1346 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1347 goto failed;
1348 }
1349
1350 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1351 if (!cmd) {
1352 err = -ENOMEM;
1353 goto failed;
1354 }
1355
1356 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1357 if (err < 0) {
1358 mgmt_pending_remove(cmd);
1359 goto failed;
1360 }
1361
1362failed:
1363 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001364 return err;
1365}
1366
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001367static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001368{
1369 struct mgmt_mode *cp = data;
1370 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001371 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001372 int err;
1373
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001374 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001375
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001376 status = mgmt_bredr_support(hdev);
1377 if (status)
1378 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1379
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001380 if (!lmp_ssp_capable(hdev))
1381 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1382 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001383
Johan Hedberga7e80f22013-01-09 16:05:19 +02001384 if (cp->val != 0x00 && cp->val != 0x01)
1385 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1386 MGMT_STATUS_INVALID_PARAMS);
1387
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001388 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001389
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001390 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001391 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001392
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001393 if (cp->val) {
1394 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1395 &hdev->dev_flags);
1396 } else {
1397 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1398 &hdev->dev_flags);
1399 if (!changed)
1400 changed = test_and_clear_bit(HCI_HS_ENABLED,
1401 &hdev->dev_flags);
1402 else
1403 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001404 }
1405
1406 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1407 if (err < 0)
1408 goto failed;
1409
1410 if (changed)
1411 err = new_settings(hdev, sk);
1412
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001413 goto failed;
1414 }
1415
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001416 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1417 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001418 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1419 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001420 goto failed;
1421 }
1422
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001423 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001424 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1425 goto failed;
1426 }
1427
1428 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1429 if (!cmd) {
1430 err = -ENOMEM;
1431 goto failed;
1432 }
1433
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001434 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001435 if (err < 0) {
1436 mgmt_pending_remove(cmd);
1437 goto failed;
1438 }
1439
1440failed:
1441 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001442 return err;
1443}
1444
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001445static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001446{
1447 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001448 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001449 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001450 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001451
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001452 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001453
Johan Hedberge6fe7982013-10-02 15:45:22 +03001454 status = mgmt_bredr_support(hdev);
1455 if (status)
1456 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001457
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001458 if (!lmp_ssp_capable(hdev))
1459 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1460 MGMT_STATUS_NOT_SUPPORTED);
1461
1462 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1463 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1464 MGMT_STATUS_REJECTED);
1465
Johan Hedberga7e80f22013-01-09 16:05:19 +02001466 if (cp->val != 0x00 && cp->val != 0x01)
1467 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1468 MGMT_STATUS_INVALID_PARAMS);
1469
Marcel Holtmannee392692013-10-01 22:59:23 -07001470 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001471
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001472 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001473 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001474 } else {
1475 if (hdev_is_powered(hdev)) {
1476 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1477 MGMT_STATUS_REJECTED);
1478 goto unlock;
1479 }
1480
Marcel Holtmannee392692013-10-01 22:59:23 -07001481 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001482 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001483
1484 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1485 if (err < 0)
1486 goto unlock;
1487
1488 if (changed)
1489 err = new_settings(hdev, sk);
1490
1491unlock:
1492 hci_dev_unlock(hdev);
1493 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001494}
1495
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001496static void le_enable_complete(struct hci_dev *hdev, u8 status)
1497{
1498 struct cmd_lookup match = { NULL, hdev };
1499
1500 if (status) {
1501 u8 mgmt_err = mgmt_status(status);
1502
1503 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1504 &mgmt_err);
1505 return;
1506 }
1507
1508 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1509
1510 new_settings(hdev, match.sk);
1511
1512 if (match.sk)
1513 sock_put(match.sk);
1514}
1515
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001516static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001517{
1518 struct mgmt_mode *cp = data;
1519 struct hci_cp_write_le_host_supported hci_cp;
1520 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001521 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001522 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001523 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001524
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001525 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001526
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001527 if (!lmp_le_capable(hdev))
1528 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1529 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001530
Johan Hedberga7e80f22013-01-09 16:05:19 +02001531 if (cp->val != 0x00 && cp->val != 0x01)
1532 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1533 MGMT_STATUS_INVALID_PARAMS);
1534
Johan Hedbergc73eee92013-04-19 18:35:21 +03001535 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001536 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001537 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1538 MGMT_STATUS_REJECTED);
1539
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001540 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001541
1542 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001543 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001544
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001545 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001546 bool changed = false;
1547
1548 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1549 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1550 changed = true;
1551 }
1552
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001553 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1554 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001555 changed = true;
1556 }
1557
Johan Hedberg06199cf2012-02-22 16:37:11 +02001558 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1559 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001560 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001561
1562 if (changed)
1563 err = new_settings(hdev, sk);
1564
Johan Hedberg1de028c2012-02-29 19:55:35 -08001565 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001566 }
1567
Johan Hedberg4375f102013-09-25 13:26:10 +03001568 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1569 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001570 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001571 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001572 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001573 }
1574
1575 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1576 if (!cmd) {
1577 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001578 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001579 }
1580
1581 memset(&hci_cp, 0, sizeof(hci_cp));
1582
1583 if (val) {
1584 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001585 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001586 }
1587
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001588 hci_req_init(&req, hdev);
1589
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001590 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && !val)
1591 disable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001592
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001593 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1594 &hci_cp);
1595
1596 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301597 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001598 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001599
Johan Hedberg1de028c2012-02-29 19:55:35 -08001600unlock:
1601 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001602 return err;
1603}
1604
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001605/* This is a helper function to test for pending mgmt commands that can
1606 * cause CoD or EIR HCI commands. We can only allow one such pending
1607 * mgmt command at a time since otherwise we cannot easily track what
1608 * the current values are, will be, and based on that calculate if a new
1609 * HCI command needs to be sent and if yes with what value.
1610 */
1611static bool pending_eir_or_class(struct hci_dev *hdev)
1612{
1613 struct pending_cmd *cmd;
1614
1615 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1616 switch (cmd->opcode) {
1617 case MGMT_OP_ADD_UUID:
1618 case MGMT_OP_REMOVE_UUID:
1619 case MGMT_OP_SET_DEV_CLASS:
1620 case MGMT_OP_SET_POWERED:
1621 return true;
1622 }
1623 }
1624
1625 return false;
1626}
1627
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001628static const u8 bluetooth_base_uuid[] = {
1629 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1630 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1631};
1632
1633static u8 get_uuid_size(const u8 *uuid)
1634{
1635 u32 val;
1636
1637 if (memcmp(uuid, bluetooth_base_uuid, 12))
1638 return 128;
1639
1640 val = get_unaligned_le32(&uuid[12]);
1641 if (val > 0xffff)
1642 return 32;
1643
1644 return 16;
1645}
1646
Johan Hedberg92da6092013-03-15 17:06:55 -05001647static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1648{
1649 struct pending_cmd *cmd;
1650
1651 hci_dev_lock(hdev);
1652
1653 cmd = mgmt_pending_find(mgmt_op, hdev);
1654 if (!cmd)
1655 goto unlock;
1656
1657 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1658 hdev->dev_class, 3);
1659
1660 mgmt_pending_remove(cmd);
1661
1662unlock:
1663 hci_dev_unlock(hdev);
1664}
1665
1666static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1667{
1668 BT_DBG("status 0x%02x", status);
1669
1670 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1671}
1672
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001673static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001674{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001675 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001676 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001677 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001678 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001679 int err;
1680
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001681 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001682
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001683 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001684
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001685 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001686 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001687 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001688 goto failed;
1689 }
1690
Andre Guedes92c4c202012-06-07 19:05:44 -03001691 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001692 if (!uuid) {
1693 err = -ENOMEM;
1694 goto failed;
1695 }
1696
1697 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001698 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001699 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001700
Johan Hedbergde66aa62013-01-27 00:31:27 +02001701 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001702
Johan Hedberg890ea892013-03-15 17:06:52 -05001703 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001704
Johan Hedberg890ea892013-03-15 17:06:52 -05001705 update_class(&req);
1706 update_eir(&req);
1707
Johan Hedberg92da6092013-03-15 17:06:55 -05001708 err = hci_req_run(&req, add_uuid_complete);
1709 if (err < 0) {
1710 if (err != -ENODATA)
1711 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001712
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001713 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001714 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001715 goto failed;
1716 }
1717
1718 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001719 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001720 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001721 goto failed;
1722 }
1723
1724 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001725
1726failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001727 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001728 return err;
1729}
1730
Johan Hedberg24b78d02012-02-23 23:24:30 +02001731static bool enable_service_cache(struct hci_dev *hdev)
1732{
1733 if (!hdev_is_powered(hdev))
1734 return false;
1735
1736 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001737 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1738 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001739 return true;
1740 }
1741
1742 return false;
1743}
1744
Johan Hedberg92da6092013-03-15 17:06:55 -05001745static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1746{
1747 BT_DBG("status 0x%02x", status);
1748
1749 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1750}
1751
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001752static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001753 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001754{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001755 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001756 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001757 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001758 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 -05001759 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001760 int err, found;
1761
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001762 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001763
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001764 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001765
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001766 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001767 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001768 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001769 goto unlock;
1770 }
1771
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001772 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1773 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001774
Johan Hedberg24b78d02012-02-23 23:24:30 +02001775 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001776 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001777 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001778 goto unlock;
1779 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001780
Johan Hedberg9246a862012-02-23 21:33:16 +02001781 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001782 }
1783
1784 found = 0;
1785
Johan Hedberg056341c2013-01-27 00:31:30 +02001786 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001787 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1788 continue;
1789
1790 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001791 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001792 found++;
1793 }
1794
1795 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001796 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001797 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001798 goto unlock;
1799 }
1800
Johan Hedberg9246a862012-02-23 21:33:16 +02001801update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001802 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001803
Johan Hedberg890ea892013-03-15 17:06:52 -05001804 update_class(&req);
1805 update_eir(&req);
1806
Johan Hedberg92da6092013-03-15 17:06:55 -05001807 err = hci_req_run(&req, remove_uuid_complete);
1808 if (err < 0) {
1809 if (err != -ENODATA)
1810 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001811
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001812 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001813 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001814 goto unlock;
1815 }
1816
1817 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001818 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001819 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001820 goto unlock;
1821 }
1822
1823 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001824
1825unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001826 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001827 return err;
1828}
1829
Johan Hedberg92da6092013-03-15 17:06:55 -05001830static void set_class_complete(struct hci_dev *hdev, u8 status)
1831{
1832 BT_DBG("status 0x%02x", status);
1833
1834 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1835}
1836
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001837static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001838 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001839{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001840 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001841 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001842 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001843 int err;
1844
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001845 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001846
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001847 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001848 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1849 MGMT_STATUS_NOT_SUPPORTED);
1850
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001851 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001852
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001853 if (pending_eir_or_class(hdev)) {
1854 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1855 MGMT_STATUS_BUSY);
1856 goto unlock;
1857 }
1858
1859 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1860 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1861 MGMT_STATUS_INVALID_PARAMS);
1862 goto unlock;
1863 }
1864
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001865 hdev->major_class = cp->major;
1866 hdev->minor_class = cp->minor;
1867
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001868 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001869 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001870 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001871 goto unlock;
1872 }
1873
Johan Hedberg890ea892013-03-15 17:06:52 -05001874 hci_req_init(&req, hdev);
1875
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001876 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001877 hci_dev_unlock(hdev);
1878 cancel_delayed_work_sync(&hdev->service_cache);
1879 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001880 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001881 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001882
Johan Hedberg890ea892013-03-15 17:06:52 -05001883 update_class(&req);
1884
Johan Hedberg92da6092013-03-15 17:06:55 -05001885 err = hci_req_run(&req, set_class_complete);
1886 if (err < 0) {
1887 if (err != -ENODATA)
1888 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001889
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001890 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001891 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001892 goto unlock;
1893 }
1894
1895 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001896 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001897 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001898 goto unlock;
1899 }
1900
1901 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001902
Johan Hedbergb5235a62012-02-21 14:32:24 +02001903unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001904 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001905 return err;
1906}
1907
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001908static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001909 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001910{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001911 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001912 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001913 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001914
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07001915 BT_DBG("request for %s", hdev->name);
1916
1917 if (!lmp_bredr_capable(hdev))
1918 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1919 MGMT_STATUS_NOT_SUPPORTED);
1920
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001921 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001922
Johan Hedberg86742e12011-11-07 23:13:38 +02001923 expected_len = sizeof(*cp) + key_count *
1924 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001925 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001926 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001927 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001928 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001929 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001930 }
1931
Johan Hedberg4ae14302013-01-20 14:27:13 +02001932 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1933 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1934 MGMT_STATUS_INVALID_PARAMS);
1935
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001936 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001937 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001938
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001939 for (i = 0; i < key_count; i++) {
1940 struct mgmt_link_key_info *key = &cp->keys[i];
1941
1942 if (key->addr.type != BDADDR_BREDR)
1943 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1944 MGMT_STATUS_INVALID_PARAMS);
1945 }
1946
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001947 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001948
1949 hci_link_keys_clear(hdev);
1950
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001951 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001952 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001953 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001954 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001955
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001956 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001957 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001958
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001959 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001960 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001961 }
1962
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001963 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001964
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001965 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001966
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001967 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001968}
1969
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001970static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001971 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001972{
1973 struct mgmt_ev_device_unpaired ev;
1974
1975 bacpy(&ev.addr.bdaddr, bdaddr);
1976 ev.addr.type = addr_type;
1977
1978 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001979 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001980}
1981
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001982static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001983 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001984{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001985 struct mgmt_cp_unpair_device *cp = data;
1986 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001987 struct hci_cp_disconnect dc;
1988 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001989 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001990 int err;
1991
Johan Hedberga8a1d192011-11-10 15:54:38 +02001992 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001993 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1994 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001995
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001996 if (!bdaddr_type_is_valid(cp->addr.type))
1997 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1998 MGMT_STATUS_INVALID_PARAMS,
1999 &rp, sizeof(rp));
2000
Johan Hedberg118da702013-01-20 14:27:20 +02002001 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2002 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2003 MGMT_STATUS_INVALID_PARAMS,
2004 &rp, sizeof(rp));
2005
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002006 hci_dev_lock(hdev);
2007
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002008 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002009 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002010 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002011 goto unlock;
2012 }
2013
Andre Guedes591f47f2012-04-24 21:02:49 -03002014 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02002015 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
2016 else
2017 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002018
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002019 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002020 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002021 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002022 goto unlock;
2023 }
2024
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002025 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002026 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002027 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002028 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002029 else
2030 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002031 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002032 } else {
2033 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002034 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002035
Johan Hedberga8a1d192011-11-10 15:54:38 +02002036 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002037 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002038 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002039 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002040 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002041 }
2042
Johan Hedberg124f6e32012-02-09 13:50:12 +02002043 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002044 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002045 if (!cmd) {
2046 err = -ENOMEM;
2047 goto unlock;
2048 }
2049
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002050 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002051 dc.reason = 0x13; /* Remote User Terminated Connection */
2052 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2053 if (err < 0)
2054 mgmt_pending_remove(cmd);
2055
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002056unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002057 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002058 return err;
2059}
2060
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002061static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002062 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002063{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002064 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002065 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002066 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002067 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002068 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002069 int err;
2070
2071 BT_DBG("");
2072
Johan Hedberg06a63b12013-01-20 14:27:21 +02002073 memset(&rp, 0, sizeof(rp));
2074 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2075 rp.addr.type = cp->addr.type;
2076
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002077 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002078 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2079 MGMT_STATUS_INVALID_PARAMS,
2080 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002081
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002082 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002083
2084 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002085 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2086 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002087 goto failed;
2088 }
2089
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002090 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002091 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2092 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002093 goto failed;
2094 }
2095
Andre Guedes591f47f2012-04-24 21:02:49 -03002096 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002097 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2098 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002099 else
2100 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002101
Vishal Agarwalf9607272012-06-13 05:32:43 +05302102 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002103 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2104 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002105 goto failed;
2106 }
2107
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002108 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002109 if (!cmd) {
2110 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002111 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002112 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002113
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002114 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002115 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002116
2117 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2118 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002119 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002120
2121failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002122 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002123 return err;
2124}
2125
Andre Guedes57c14772012-04-24 21:02:50 -03002126static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002127{
2128 switch (link_type) {
2129 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002130 switch (addr_type) {
2131 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002132 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002133
Johan Hedberg48264f02011-11-09 13:58:58 +02002134 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002135 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002136 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002137 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002138
Johan Hedberg4c659c32011-11-07 23:13:39 +02002139 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002140 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002141 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002142 }
2143}
2144
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002145static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2146 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002147{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002148 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002149 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002150 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002151 int err;
2152 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002153
2154 BT_DBG("");
2155
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002156 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002157
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002158 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002159 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002160 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002161 goto unlock;
2162 }
2163
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002164 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002165 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2166 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002167 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002168 }
2169
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002170 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002171 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002172 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002173 err = -ENOMEM;
2174 goto unlock;
2175 }
2176
Johan Hedberg2784eb42011-01-21 13:56:35 +02002177 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002178 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002179 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2180 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002181 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002182 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002183 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002184 continue;
2185 i++;
2186 }
2187
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002188 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002189
Johan Hedberg4c659c32011-11-07 23:13:39 +02002190 /* Recalculate length in case of filtered SCO connections, etc */
2191 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002192
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002193 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002194 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002195
Johan Hedberga38528f2011-01-22 06:46:43 +02002196 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002197
2198unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002199 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002200 return err;
2201}
2202
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002203static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002204 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002205{
2206 struct pending_cmd *cmd;
2207 int err;
2208
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002209 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002210 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002211 if (!cmd)
2212 return -ENOMEM;
2213
Johan Hedbergd8457692012-02-17 14:24:57 +02002214 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002215 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002216 if (err < 0)
2217 mgmt_pending_remove(cmd);
2218
2219 return err;
2220}
2221
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002222static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002223 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002224{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002225 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002226 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002227 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002228 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002229 int err;
2230
2231 BT_DBG("");
2232
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002233 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002234
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002235 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002236 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002237 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002238 goto failed;
2239 }
2240
Johan Hedbergd8457692012-02-17 14:24:57 +02002241 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002242 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002243 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002244 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002245 goto failed;
2246 }
2247
2248 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002249 struct mgmt_cp_pin_code_neg_reply ncp;
2250
2251 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002252
2253 BT_ERR("PIN code is not 16 bytes long");
2254
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002255 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002256 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002257 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002258 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002259
2260 goto failed;
2261 }
2262
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002263 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002264 if (!cmd) {
2265 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002266 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002267 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002268
Johan Hedbergd8457692012-02-17 14:24:57 +02002269 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002270 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002271 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002272
2273 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2274 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002275 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002276
2277failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002278 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002279 return err;
2280}
2281
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002282static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2283 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002284{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002285 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002286
2287 BT_DBG("");
2288
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002289 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002290
2291 hdev->io_capability = cp->io_capability;
2292
2293 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002294 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002295
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002296 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002297
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002298 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2299 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002300}
2301
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002302static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002303{
2304 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002305 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002306
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002307 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002308 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2309 continue;
2310
Johan Hedberge9a416b2011-02-19 12:05:56 -03002311 if (cmd->user_data != conn)
2312 continue;
2313
2314 return cmd;
2315 }
2316
2317 return NULL;
2318}
2319
2320static void pairing_complete(struct pending_cmd *cmd, u8 status)
2321{
2322 struct mgmt_rp_pair_device rp;
2323 struct hci_conn *conn = cmd->user_data;
2324
Johan Hedbergba4e5642011-11-11 00:07:34 +02002325 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002326 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002327
Johan Hedbergaee9b212012-02-18 15:07:59 +02002328 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002329 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002330
2331 /* So we don't get further callbacks for this connection */
2332 conn->connect_cfm_cb = NULL;
2333 conn->security_cfm_cb = NULL;
2334 conn->disconn_cfm_cb = NULL;
2335
David Herrmann76a68ba2013-04-06 20:28:37 +02002336 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002337
Johan Hedberga664b5b2011-02-19 12:06:02 -03002338 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002339}
2340
2341static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2342{
2343 struct pending_cmd *cmd;
2344
2345 BT_DBG("status %u", status);
2346
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002347 cmd = find_pairing(conn);
2348 if (!cmd)
2349 BT_DBG("Unable to find a pending command");
2350 else
Johan Hedberge2113262012-02-18 15:20:03 +02002351 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002352}
2353
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302354static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2355{
2356 struct pending_cmd *cmd;
2357
2358 BT_DBG("status %u", status);
2359
2360 if (!status)
2361 return;
2362
2363 cmd = find_pairing(conn);
2364 if (!cmd)
2365 BT_DBG("Unable to find a pending command");
2366 else
2367 pairing_complete(cmd, mgmt_status(status));
2368}
2369
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002370static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002371 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002372{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002373 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002374 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002375 struct pending_cmd *cmd;
2376 u8 sec_level, auth_type;
2377 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002378 int err;
2379
2380 BT_DBG("");
2381
Szymon Jancf950a30e2013-01-18 12:48:07 +01002382 memset(&rp, 0, sizeof(rp));
2383 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2384 rp.addr.type = cp->addr.type;
2385
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002386 if (!bdaddr_type_is_valid(cp->addr.type))
2387 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2388 MGMT_STATUS_INVALID_PARAMS,
2389 &rp, sizeof(rp));
2390
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002391 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002392
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002393 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002394 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2395 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002396 goto unlock;
2397 }
2398
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002399 sec_level = BT_SECURITY_MEDIUM;
2400 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002401 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002402 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002403 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002404
Andre Guedes591f47f2012-04-24 21:02:49 -03002405 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002406 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2407 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002408 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002409 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2410 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002411
Ville Tervo30e76272011-02-22 16:10:53 -03002412 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002413 int status;
2414
2415 if (PTR_ERR(conn) == -EBUSY)
2416 status = MGMT_STATUS_BUSY;
2417 else
2418 status = MGMT_STATUS_CONNECT_FAILED;
2419
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002420 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002421 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002422 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002423 goto unlock;
2424 }
2425
2426 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002427 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002428 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002429 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002430 goto unlock;
2431 }
2432
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002433 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002434 if (!cmd) {
2435 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002436 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002437 goto unlock;
2438 }
2439
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002440 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002441 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002442 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302443 else
2444 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002445
Johan Hedberge9a416b2011-02-19 12:05:56 -03002446 conn->security_cfm_cb = pairing_complete_cb;
2447 conn->disconn_cfm_cb = pairing_complete_cb;
2448 conn->io_capability = cp->io_cap;
2449 cmd->user_data = conn;
2450
2451 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002452 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002453 pairing_complete(cmd, 0);
2454
2455 err = 0;
2456
2457unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002458 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002459 return err;
2460}
2461
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002462static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2463 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002464{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002465 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002466 struct pending_cmd *cmd;
2467 struct hci_conn *conn;
2468 int err;
2469
2470 BT_DBG("");
2471
Johan Hedberg28424702012-02-02 04:02:29 +02002472 hci_dev_lock(hdev);
2473
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002474 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002475 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002476 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002477 goto unlock;
2478 }
2479
Johan Hedberg28424702012-02-02 04:02:29 +02002480 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2481 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002482 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002483 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002484 goto unlock;
2485 }
2486
2487 conn = cmd->user_data;
2488
2489 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002490 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002491 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002492 goto unlock;
2493 }
2494
2495 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2496
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002497 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002498 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002499unlock:
2500 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002501 return err;
2502}
2503
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002504static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002505 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002506 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002507{
Johan Hedberga5c29682011-02-19 12:05:57 -03002508 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002509 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002510 int err;
2511
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002512 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002513
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002514 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002515 err = cmd_complete(sk, hdev->id, mgmt_op,
2516 MGMT_STATUS_NOT_POWERED, addr,
2517 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002518 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002519 }
2520
Johan Hedberg1707c602013-03-15 17:07:15 -05002521 if (addr->type == BDADDR_BREDR)
2522 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002523 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002524 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002525
Johan Hedberg272d90d2012-02-09 15:26:12 +02002526 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002527 err = cmd_complete(sk, hdev->id, mgmt_op,
2528 MGMT_STATUS_NOT_CONNECTED, addr,
2529 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002530 goto done;
2531 }
2532
Johan Hedberg1707c602013-03-15 17:07:15 -05002533 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002534 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002535 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002536
Brian Gix5fe57d92011-12-21 16:12:13 -08002537 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002538 err = cmd_complete(sk, hdev->id, mgmt_op,
2539 MGMT_STATUS_SUCCESS, addr,
2540 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002541 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002542 err = cmd_complete(sk, hdev->id, mgmt_op,
2543 MGMT_STATUS_FAILED, addr,
2544 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002545
Brian Gix47c15e22011-11-16 13:53:14 -08002546 goto done;
2547 }
2548
Johan Hedberg1707c602013-03-15 17:07:15 -05002549 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002550 if (!cmd) {
2551 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002552 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002553 }
2554
Brian Gix0df4c182011-11-16 13:53:13 -08002555 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002556 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2557 struct hci_cp_user_passkey_reply cp;
2558
Johan Hedberg1707c602013-03-15 17:07:15 -05002559 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002560 cp.passkey = passkey;
2561 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2562 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002563 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2564 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002565
Johan Hedberga664b5b2011-02-19 12:06:02 -03002566 if (err < 0)
2567 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002568
Brian Gix0df4c182011-11-16 13:53:13 -08002569done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002570 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002571 return err;
2572}
2573
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302574static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2575 void *data, u16 len)
2576{
2577 struct mgmt_cp_pin_code_neg_reply *cp = data;
2578
2579 BT_DBG("");
2580
Johan Hedberg1707c602013-03-15 17:07:15 -05002581 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302582 MGMT_OP_PIN_CODE_NEG_REPLY,
2583 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2584}
2585
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002586static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2587 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002588{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002589 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002590
2591 BT_DBG("");
2592
2593 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002594 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002595 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002596
Johan Hedberg1707c602013-03-15 17:07:15 -05002597 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002598 MGMT_OP_USER_CONFIRM_REPLY,
2599 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002600}
2601
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002602static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002603 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002604{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002605 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002606
2607 BT_DBG("");
2608
Johan Hedberg1707c602013-03-15 17:07:15 -05002609 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002610 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2611 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002612}
2613
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002614static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2615 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002616{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002617 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002618
2619 BT_DBG("");
2620
Johan Hedberg1707c602013-03-15 17:07:15 -05002621 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002622 MGMT_OP_USER_PASSKEY_REPLY,
2623 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002624}
2625
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002626static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002627 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002628{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002629 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002630
2631 BT_DBG("");
2632
Johan Hedberg1707c602013-03-15 17:07:15 -05002633 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002634 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2635 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002636}
2637
Johan Hedberg13928972013-03-15 17:07:00 -05002638static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002639{
Johan Hedberg13928972013-03-15 17:07:00 -05002640 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002641 struct hci_cp_write_local_name cp;
2642
Johan Hedberg13928972013-03-15 17:07:00 -05002643 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002644
Johan Hedberg890ea892013-03-15 17:06:52 -05002645 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002646}
2647
Johan Hedberg13928972013-03-15 17:07:00 -05002648static void set_name_complete(struct hci_dev *hdev, u8 status)
2649{
2650 struct mgmt_cp_set_local_name *cp;
2651 struct pending_cmd *cmd;
2652
2653 BT_DBG("status 0x%02x", status);
2654
2655 hci_dev_lock(hdev);
2656
2657 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2658 if (!cmd)
2659 goto unlock;
2660
2661 cp = cmd->param;
2662
2663 if (status)
2664 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2665 mgmt_status(status));
2666 else
2667 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2668 cp, sizeof(*cp));
2669
2670 mgmt_pending_remove(cmd);
2671
2672unlock:
2673 hci_dev_unlock(hdev);
2674}
2675
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002676static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002677 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002678{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002679 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002680 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002681 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002682 int err;
2683
2684 BT_DBG("");
2685
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002686 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002687
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002688 /* If the old values are the same as the new ones just return a
2689 * direct command complete event.
2690 */
2691 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2692 !memcmp(hdev->short_name, cp->short_name,
2693 sizeof(hdev->short_name))) {
2694 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2695 data, len);
2696 goto failed;
2697 }
2698
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002699 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002700
Johan Hedbergb5235a62012-02-21 14:32:24 +02002701 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002702 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002703
2704 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002705 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002706 if (err < 0)
2707 goto failed;
2708
2709 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002710 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002711
Johan Hedbergb5235a62012-02-21 14:32:24 +02002712 goto failed;
2713 }
2714
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002715 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002716 if (!cmd) {
2717 err = -ENOMEM;
2718 goto failed;
2719 }
2720
Johan Hedberg13928972013-03-15 17:07:00 -05002721 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2722
Johan Hedberg890ea892013-03-15 17:06:52 -05002723 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002724
2725 if (lmp_bredr_capable(hdev)) {
2726 update_name(&req);
2727 update_eir(&req);
2728 }
2729
2730 if (lmp_le_capable(hdev))
2731 hci_update_ad(&req);
2732
Johan Hedberg13928972013-03-15 17:07:00 -05002733 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002734 if (err < 0)
2735 mgmt_pending_remove(cmd);
2736
2737failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002738 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002739 return err;
2740}
2741
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002742static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002743 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002744{
Szymon Jancc35938b2011-03-22 13:12:21 +01002745 struct pending_cmd *cmd;
2746 int err;
2747
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002748 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002749
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002750 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002751
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002752 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002753 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002754 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002755 goto unlock;
2756 }
2757
Andre Guedes9a1a1992012-07-24 15:03:48 -03002758 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002759 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002760 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002761 goto unlock;
2762 }
2763
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002764 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002765 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002766 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002767 goto unlock;
2768 }
2769
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002770 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002771 if (!cmd) {
2772 err = -ENOMEM;
2773 goto unlock;
2774 }
2775
2776 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2777 if (err < 0)
2778 mgmt_pending_remove(cmd);
2779
2780unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002781 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002782 return err;
2783}
2784
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002785static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002786 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002787{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002788 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002789 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002790 int err;
2791
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002792 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002793
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002794 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002795
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002796 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002797 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002798 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002799 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002800 else
Szymon Janca6785be2012-12-13 15:11:21 +01002801 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002802
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002803 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002804 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002805
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002806 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002807 return err;
2808}
2809
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002810static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002811 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002812{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002813 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002814 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002815 int err;
2816
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002817 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002818
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002819 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002820
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002821 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002822 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002823 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002824 else
Szymon Janca6785be2012-12-13 15:11:21 +01002825 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002826
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002827 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002828 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002829
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002830 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002831 return err;
2832}
2833
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002834static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2835{
2836 struct pending_cmd *cmd;
2837 u8 type;
2838 int err;
2839
2840 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2841
2842 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2843 if (!cmd)
2844 return -ENOENT;
2845
2846 type = hdev->discovery.type;
2847
2848 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2849 &type, sizeof(type));
2850 mgmt_pending_remove(cmd);
2851
2852 return err;
2853}
2854
Andre Guedes7c307722013-04-30 15:29:28 -03002855static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2856{
2857 BT_DBG("status %d", status);
2858
2859 if (status) {
2860 hci_dev_lock(hdev);
2861 mgmt_start_discovery_failed(hdev, status);
2862 hci_dev_unlock(hdev);
2863 return;
2864 }
2865
2866 hci_dev_lock(hdev);
2867 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2868 hci_dev_unlock(hdev);
2869
2870 switch (hdev->discovery.type) {
2871 case DISCOV_TYPE_LE:
2872 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002873 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002874 break;
2875
2876 case DISCOV_TYPE_INTERLEAVED:
2877 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002878 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002879 break;
2880
2881 case DISCOV_TYPE_BREDR:
2882 break;
2883
2884 default:
2885 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2886 }
2887}
2888
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002889static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002890 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002891{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002892 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002893 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002894 struct hci_cp_le_set_scan_param param_cp;
2895 struct hci_cp_le_set_scan_enable enable_cp;
2896 struct hci_cp_inquiry inq_cp;
2897 struct hci_request req;
2898 /* General inquiry access code (GIAC) */
2899 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03002900 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04002901 int err;
2902
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002903 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002904
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002905 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002906
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002907 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002908 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002909 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002910 goto failed;
2911 }
2912
Andre Guedes642be6c2012-03-21 00:03:37 -03002913 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2914 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2915 MGMT_STATUS_BUSY);
2916 goto failed;
2917 }
2918
Johan Hedbergff9ef572012-01-04 14:23:45 +02002919 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002920 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002921 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002922 goto failed;
2923 }
2924
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002925 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002926 if (!cmd) {
2927 err = -ENOMEM;
2928 goto failed;
2929 }
2930
Andre Guedes4aab14e2012-02-17 20:39:36 -03002931 hdev->discovery.type = cp->type;
2932
Andre Guedes7c307722013-04-30 15:29:28 -03002933 hci_req_init(&req, hdev);
2934
Andre Guedes4aab14e2012-02-17 20:39:36 -03002935 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002936 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002937 status = mgmt_bredr_support(hdev);
2938 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002939 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002940 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002941 mgmt_pending_remove(cmd);
2942 goto failed;
2943 }
2944
Andre Guedes7c307722013-04-30 15:29:28 -03002945 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2946 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2947 MGMT_STATUS_BUSY);
2948 mgmt_pending_remove(cmd);
2949 goto failed;
2950 }
2951
2952 hci_inquiry_cache_flush(hdev);
2953
2954 memset(&inq_cp, 0, sizeof(inq_cp));
2955 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002956 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002957 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002958 break;
2959
2960 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002961 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002962 status = mgmt_le_support(hdev);
2963 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002964 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002965 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002966 mgmt_pending_remove(cmd);
2967 goto failed;
2968 }
2969
Andre Guedes7c307722013-04-30 15:29:28 -03002970 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002971 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002972 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2973 MGMT_STATUS_NOT_SUPPORTED);
2974 mgmt_pending_remove(cmd);
2975 goto failed;
2976 }
2977
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02002978 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03002979 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2980 MGMT_STATUS_REJECTED);
2981 mgmt_pending_remove(cmd);
2982 goto failed;
2983 }
2984
2985 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2986 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2987 MGMT_STATUS_BUSY);
2988 mgmt_pending_remove(cmd);
2989 goto failed;
2990 }
2991
2992 memset(&param_cp, 0, sizeof(param_cp));
2993 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002994 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2995 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07002996 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
2997 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
2998 else
2999 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03003000 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3001 &param_cp);
3002
3003 memset(&enable_cp, 0, sizeof(enable_cp));
3004 enable_cp.enable = LE_SCAN_ENABLE;
3005 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3006 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3007 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003008 break;
3009
Andre Guedesf39799f2012-02-17 20:39:35 -03003010 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003011 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3012 MGMT_STATUS_INVALID_PARAMS);
3013 mgmt_pending_remove(cmd);
3014 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003015 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003016
Andre Guedes7c307722013-04-30 15:29:28 -03003017 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003018 if (err < 0)
3019 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003020 else
3021 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003022
3023failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003024 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003025 return err;
3026}
3027
Andre Guedes1183fdc2013-04-30 15:29:35 -03003028static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3029{
3030 struct pending_cmd *cmd;
3031 int err;
3032
3033 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3034 if (!cmd)
3035 return -ENOENT;
3036
3037 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3038 &hdev->discovery.type, sizeof(hdev->discovery.type));
3039 mgmt_pending_remove(cmd);
3040
3041 return err;
3042}
3043
Andre Guedes0e05bba2013-04-30 15:29:33 -03003044static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3045{
3046 BT_DBG("status %d", status);
3047
3048 hci_dev_lock(hdev);
3049
3050 if (status) {
3051 mgmt_stop_discovery_failed(hdev, status);
3052 goto unlock;
3053 }
3054
3055 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3056
3057unlock:
3058 hci_dev_unlock(hdev);
3059}
3060
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003061static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003062 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003063{
Johan Hedbergd9306502012-02-20 23:25:18 +02003064 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003065 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003066 struct hci_cp_remote_name_req_cancel cp;
3067 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003068 struct hci_request req;
3069 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003070 int err;
3071
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003072 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003073
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003074 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003075
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003076 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003077 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003078 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3079 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003080 goto unlock;
3081 }
3082
3083 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003084 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003085 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3086 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003087 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003088 }
3089
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003090 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003091 if (!cmd) {
3092 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003093 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003094 }
3095
Andre Guedes0e05bba2013-04-30 15:29:33 -03003096 hci_req_init(&req, hdev);
3097
Andre Guedese0d9727e2012-03-20 15:15:36 -03003098 switch (hdev->discovery.state) {
3099 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003100 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3101 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3102 } else {
3103 cancel_delayed_work(&hdev->le_scan_disable);
3104
3105 memset(&enable_cp, 0, sizeof(enable_cp));
3106 enable_cp.enable = LE_SCAN_DISABLE;
3107 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3108 sizeof(enable_cp), &enable_cp);
3109 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003110
Andre Guedese0d9727e2012-03-20 15:15:36 -03003111 break;
3112
3113 case DISCOVERY_RESOLVING:
3114 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003115 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003116 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003117 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003118 err = cmd_complete(sk, hdev->id,
3119 MGMT_OP_STOP_DISCOVERY, 0,
3120 &mgmt_cp->type,
3121 sizeof(mgmt_cp->type));
3122 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3123 goto unlock;
3124 }
3125
3126 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003127 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3128 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003129
3130 break;
3131
3132 default:
3133 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003134
3135 mgmt_pending_remove(cmd);
3136 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3137 MGMT_STATUS_FAILED, &mgmt_cp->type,
3138 sizeof(mgmt_cp->type));
3139 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003140 }
3141
Andre Guedes0e05bba2013-04-30 15:29:33 -03003142 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003143 if (err < 0)
3144 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003145 else
3146 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003147
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003148unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003149 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003150 return err;
3151}
3152
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003153static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003154 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003155{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003156 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003157 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003158 int err;
3159
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003160 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003161
Johan Hedberg561aafb2012-01-04 13:31:59 +02003162 hci_dev_lock(hdev);
3163
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003164 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003165 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003166 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003167 goto failed;
3168 }
3169
Johan Hedberga198e7b2012-02-17 14:27:06 +02003170 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003171 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003172 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003173 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003174 goto failed;
3175 }
3176
3177 if (cp->name_known) {
3178 e->name_state = NAME_KNOWN;
3179 list_del(&e->list);
3180 } else {
3181 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003182 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003183 }
3184
Johan Hedberge3846622013-01-09 15:29:33 +02003185 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3186 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003187
3188failed:
3189 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003190 return err;
3191}
3192
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003193static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003194 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003195{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003196 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003197 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003198 int err;
3199
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003200 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003201
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003202 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003203 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3204 MGMT_STATUS_INVALID_PARAMS,
3205 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003206
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003207 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003208
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003209 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003210 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003211 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003212 else
Szymon Janca6785be2012-12-13 15:11:21 +01003213 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003214
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003215 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003216 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003217
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003218 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003219
3220 return err;
3221}
3222
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003223static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003224 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003225{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003226 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003227 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003228 int err;
3229
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003230 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003231
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003232 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003233 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3234 MGMT_STATUS_INVALID_PARAMS,
3235 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003236
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003237 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003238
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003239 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003240 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003241 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003242 else
Szymon Janca6785be2012-12-13 15:11:21 +01003243 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003244
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003245 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003246 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003247
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003248 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003249
3250 return err;
3251}
3252
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003253static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3254 u16 len)
3255{
3256 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003257 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003258 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003259 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003260
3261 BT_DBG("%s", hdev->name);
3262
Szymon Jancc72d4b82012-03-16 16:02:57 +01003263 source = __le16_to_cpu(cp->source);
3264
3265 if (source > 0x0002)
3266 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3267 MGMT_STATUS_INVALID_PARAMS);
3268
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003269 hci_dev_lock(hdev);
3270
Szymon Jancc72d4b82012-03-16 16:02:57 +01003271 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003272 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3273 hdev->devid_product = __le16_to_cpu(cp->product);
3274 hdev->devid_version = __le16_to_cpu(cp->version);
3275
3276 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3277
Johan Hedberg890ea892013-03-15 17:06:52 -05003278 hci_req_init(&req, hdev);
3279 update_eir(&req);
3280 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003281
3282 hci_dev_unlock(hdev);
3283
3284 return err;
3285}
3286
Johan Hedberg4375f102013-09-25 13:26:10 +03003287static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3288{
3289 struct cmd_lookup match = { NULL, hdev };
3290
3291 if (status) {
3292 u8 mgmt_err = mgmt_status(status);
3293
3294 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3295 cmd_status_rsp, &mgmt_err);
3296 return;
3297 }
3298
3299 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3300 &match);
3301
3302 new_settings(hdev, match.sk);
3303
3304 if (match.sk)
3305 sock_put(match.sk);
3306}
3307
Marcel Holtmann21b51872013-10-10 09:47:53 -07003308static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3309 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003310{
3311 struct mgmt_mode *cp = data;
3312 struct pending_cmd *cmd;
3313 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003314 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003315 int err;
3316
3317 BT_DBG("request for %s", hdev->name);
3318
Johan Hedberge6fe7982013-10-02 15:45:22 +03003319 status = mgmt_le_support(hdev);
3320 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003321 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003322 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003323
3324 if (cp->val != 0x00 && cp->val != 0x01)
3325 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3326 MGMT_STATUS_INVALID_PARAMS);
3327
3328 hci_dev_lock(hdev);
3329
3330 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003331 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003332
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003333 /* The following conditions are ones which mean that we should
3334 * not do any HCI communication but directly send a mgmt
3335 * response to user space (after toggling the flag if
3336 * necessary).
3337 */
3338 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003339 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003340 bool changed = false;
3341
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003342 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3343 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003344 changed = true;
3345 }
3346
3347 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3348 if (err < 0)
3349 goto unlock;
3350
3351 if (changed)
3352 err = new_settings(hdev, sk);
3353
3354 goto unlock;
3355 }
3356
3357 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3358 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3359 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3360 MGMT_STATUS_BUSY);
3361 goto unlock;
3362 }
3363
3364 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3365 if (!cmd) {
3366 err = -ENOMEM;
3367 goto unlock;
3368 }
3369
3370 hci_req_init(&req, hdev);
3371
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003372 if (val)
3373 enable_advertising(&req);
3374 else
3375 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003376
3377 err = hci_req_run(&req, set_advertising_complete);
3378 if (err < 0)
3379 mgmt_pending_remove(cmd);
3380
3381unlock:
3382 hci_dev_unlock(hdev);
3383 return err;
3384}
3385
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003386static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3387 void *data, u16 len)
3388{
3389 struct mgmt_cp_set_static_address *cp = data;
3390 int err;
3391
3392 BT_DBG("%s", hdev->name);
3393
Marcel Holtmann62af4442013-10-02 22:10:32 -07003394 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003395 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003396 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003397
3398 if (hdev_is_powered(hdev))
3399 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3400 MGMT_STATUS_REJECTED);
3401
3402 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3403 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3404 return cmd_status(sk, hdev->id,
3405 MGMT_OP_SET_STATIC_ADDRESS,
3406 MGMT_STATUS_INVALID_PARAMS);
3407
3408 /* Two most significant bits shall be set */
3409 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3410 return cmd_status(sk, hdev->id,
3411 MGMT_OP_SET_STATIC_ADDRESS,
3412 MGMT_STATUS_INVALID_PARAMS);
3413 }
3414
3415 hci_dev_lock(hdev);
3416
3417 bacpy(&hdev->static_addr, &cp->bdaddr);
3418
3419 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3420
3421 hci_dev_unlock(hdev);
3422
3423 return err;
3424}
3425
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003426static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3427 void *data, u16 len)
3428{
3429 struct mgmt_cp_set_scan_params *cp = data;
3430 __u16 interval, window;
3431 int err;
3432
3433 BT_DBG("%s", hdev->name);
3434
3435 if (!lmp_le_capable(hdev))
3436 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3437 MGMT_STATUS_NOT_SUPPORTED);
3438
3439 interval = __le16_to_cpu(cp->interval);
3440
3441 if (interval < 0x0004 || interval > 0x4000)
3442 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3443 MGMT_STATUS_INVALID_PARAMS);
3444
3445 window = __le16_to_cpu(cp->window);
3446
3447 if (window < 0x0004 || window > 0x4000)
3448 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3449 MGMT_STATUS_INVALID_PARAMS);
3450
3451 hci_dev_lock(hdev);
3452
3453 hdev->le_scan_interval = interval;
3454 hdev->le_scan_window = window;
3455
3456 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3457
3458 hci_dev_unlock(hdev);
3459
3460 return err;
3461}
3462
Johan Hedberg33e38b32013-03-15 17:07:05 -05003463static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3464{
3465 struct pending_cmd *cmd;
3466
3467 BT_DBG("status 0x%02x", status);
3468
3469 hci_dev_lock(hdev);
3470
3471 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3472 if (!cmd)
3473 goto unlock;
3474
3475 if (status) {
3476 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3477 mgmt_status(status));
3478 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003479 struct mgmt_mode *cp = cmd->param;
3480
3481 if (cp->val)
3482 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3483 else
3484 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3485
Johan Hedberg33e38b32013-03-15 17:07:05 -05003486 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3487 new_settings(hdev, cmd->sk);
3488 }
3489
3490 mgmt_pending_remove(cmd);
3491
3492unlock:
3493 hci_dev_unlock(hdev);
3494}
3495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003496static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003497 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003498{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003499 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003500 struct pending_cmd *cmd;
3501 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003502 int err;
3503
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003504 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003505
Johan Hedberg56f87902013-10-02 13:43:13 +03003506 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3507 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003508 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3509 MGMT_STATUS_NOT_SUPPORTED);
3510
Johan Hedberga7e80f22013-01-09 16:05:19 +02003511 if (cp->val != 0x00 && cp->val != 0x01)
3512 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3513 MGMT_STATUS_INVALID_PARAMS);
3514
Johan Hedberg5400c042012-02-21 16:40:33 +02003515 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003516 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003517 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003518
3519 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003520 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003521 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003522
3523 hci_dev_lock(hdev);
3524
Johan Hedberg05cbf292013-03-15 17:07:07 -05003525 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3526 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3527 MGMT_STATUS_BUSY);
3528 goto unlock;
3529 }
3530
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003531 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3532 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3533 hdev);
3534 goto unlock;
3535 }
3536
Johan Hedberg33e38b32013-03-15 17:07:05 -05003537 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3538 data, len);
3539 if (!cmd) {
3540 err = -ENOMEM;
3541 goto unlock;
3542 }
3543
3544 hci_req_init(&req, hdev);
3545
Johan Hedberg406d7802013-03-15 17:07:09 -05003546 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003547
3548 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003549 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003550 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003551 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003552 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003553 }
3554
Johan Hedberg33e38b32013-03-15 17:07:05 -05003555unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003556 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003557
Antti Julkuf6422ec2011-06-22 13:11:56 +03003558 return err;
3559}
3560
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003561static void set_bredr_scan(struct hci_request *req)
3562{
3563 struct hci_dev *hdev = req->hdev;
3564 u8 scan = 0;
3565
3566 /* Ensure that fast connectable is disabled. This function will
3567 * not do anything if the page scan parameters are already what
3568 * they should be.
3569 */
3570 write_fast_connectable(req, false);
3571
3572 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3573 scan |= SCAN_PAGE;
3574 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3575 scan |= SCAN_INQUIRY;
3576
3577 if (scan)
3578 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3579}
3580
Johan Hedberg0663ca22013-10-02 13:43:14 +03003581static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3582{
3583 struct pending_cmd *cmd;
3584
3585 BT_DBG("status 0x%02x", status);
3586
3587 hci_dev_lock(hdev);
3588
3589 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3590 if (!cmd)
3591 goto unlock;
3592
3593 if (status) {
3594 u8 mgmt_err = mgmt_status(status);
3595
3596 /* We need to restore the flag if related HCI commands
3597 * failed.
3598 */
3599 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3600
3601 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3602 } else {
3603 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3604 new_settings(hdev, cmd->sk);
3605 }
3606
3607 mgmt_pending_remove(cmd);
3608
3609unlock:
3610 hci_dev_unlock(hdev);
3611}
3612
3613static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3614{
3615 struct mgmt_mode *cp = data;
3616 struct pending_cmd *cmd;
3617 struct hci_request req;
3618 int err;
3619
3620 BT_DBG("request for %s", hdev->name);
3621
3622 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3623 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3624 MGMT_STATUS_NOT_SUPPORTED);
3625
3626 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3627 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3628 MGMT_STATUS_REJECTED);
3629
3630 if (cp->val != 0x00 && cp->val != 0x01)
3631 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3632 MGMT_STATUS_INVALID_PARAMS);
3633
3634 hci_dev_lock(hdev);
3635
3636 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3637 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3638 goto unlock;
3639 }
3640
3641 if (!hdev_is_powered(hdev)) {
3642 if (!cp->val) {
3643 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3644 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3645 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3646 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3647 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3648 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3649 }
3650
3651 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3652
3653 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3654 if (err < 0)
3655 goto unlock;
3656
3657 err = new_settings(hdev, sk);
3658 goto unlock;
3659 }
3660
3661 /* Reject disabling when powered on */
3662 if (!cp->val) {
3663 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3664 MGMT_STATUS_REJECTED);
3665 goto unlock;
3666 }
3667
3668 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3669 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3670 MGMT_STATUS_BUSY);
3671 goto unlock;
3672 }
3673
3674 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3675 if (!cmd) {
3676 err = -ENOMEM;
3677 goto unlock;
3678 }
3679
3680 /* We need to flip the bit already here so that hci_update_ad
3681 * generates the correct flags.
3682 */
3683 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3684
3685 hci_req_init(&req, hdev);
3686 hci_update_ad(&req);
3687 err = hci_req_run(&req, set_bredr_complete);
3688 if (err < 0)
3689 mgmt_pending_remove(cmd);
3690
3691unlock:
3692 hci_dev_unlock(hdev);
3693 return err;
3694}
3695
Johan Hedberg3f706b72013-01-20 14:27:16 +02003696static bool ltk_is_valid(struct mgmt_ltk_info *key)
3697{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003698 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3699 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003700 if (key->master != 0x00 && key->master != 0x01)
3701 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003702 if (!bdaddr_type_is_le(key->addr.type))
3703 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003704 return true;
3705}
3706
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003707static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003708 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003709{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003710 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3711 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003712 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003713
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003714 BT_DBG("request for %s", hdev->name);
3715
3716 if (!lmp_le_capable(hdev))
3717 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3718 MGMT_STATUS_NOT_SUPPORTED);
3719
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003720 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003721
3722 expected_len = sizeof(*cp) + key_count *
3723 sizeof(struct mgmt_ltk_info);
3724 if (expected_len != len) {
3725 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003726 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003727 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003728 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003729 }
3730
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003731 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003732
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003733 for (i = 0; i < key_count; i++) {
3734 struct mgmt_ltk_info *key = &cp->keys[i];
3735
Johan Hedberg3f706b72013-01-20 14:27:16 +02003736 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003737 return cmd_status(sk, hdev->id,
3738 MGMT_OP_LOAD_LONG_TERM_KEYS,
3739 MGMT_STATUS_INVALID_PARAMS);
3740 }
3741
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003742 hci_dev_lock(hdev);
3743
3744 hci_smp_ltks_clear(hdev);
3745
3746 for (i = 0; i < key_count; i++) {
3747 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003748 u8 type, addr_type;
3749
3750 if (key->addr.type == BDADDR_LE_PUBLIC)
3751 addr_type = ADDR_LE_DEV_PUBLIC;
3752 else
3753 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003754
3755 if (key->master)
3756 type = HCI_SMP_LTK;
3757 else
3758 type = HCI_SMP_LTK_SLAVE;
3759
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003760 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003761 type, 0, key->authenticated, key->val,
3762 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003763 }
3764
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003765 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3766 NULL, 0);
3767
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003768 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003769
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003770 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003771}
3772
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003773static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003774 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3775 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003776 bool var_len;
3777 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003778} mgmt_handlers[] = {
3779 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003780 { read_version, false, MGMT_READ_VERSION_SIZE },
3781 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3782 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3783 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3784 { set_powered, false, MGMT_SETTING_SIZE },
3785 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3786 { set_connectable, false, MGMT_SETTING_SIZE },
3787 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3788 { set_pairable, false, MGMT_SETTING_SIZE },
3789 { set_link_security, false, MGMT_SETTING_SIZE },
3790 { set_ssp, false, MGMT_SETTING_SIZE },
3791 { set_hs, false, MGMT_SETTING_SIZE },
3792 { set_le, false, MGMT_SETTING_SIZE },
3793 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3794 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3795 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3796 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3797 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3798 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3799 { disconnect, false, MGMT_DISCONNECT_SIZE },
3800 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3801 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3802 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3803 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3804 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3805 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3806 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3807 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3808 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3809 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3810 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3811 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3812 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3813 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3814 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3815 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3816 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3817 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3818 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003819 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003820 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003821 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003822 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003823 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003824};
3825
3826
Johan Hedberg03811012010-12-08 00:21:06 +02003827int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3828{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003829 void *buf;
3830 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003831 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003832 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003833 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003834 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003835 int err;
3836
3837 BT_DBG("got %zu bytes", msglen);
3838
3839 if (msglen < sizeof(*hdr))
3840 return -EINVAL;
3841
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003842 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003843 if (!buf)
3844 return -ENOMEM;
3845
3846 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3847 err = -EFAULT;
3848 goto done;
3849 }
3850
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003851 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003852 opcode = __le16_to_cpu(hdr->opcode);
3853 index = __le16_to_cpu(hdr->index);
3854 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003855
3856 if (len != msglen - sizeof(*hdr)) {
3857 err = -EINVAL;
3858 goto done;
3859 }
3860
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003861 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003862 hdev = hci_dev_get(index);
3863 if (!hdev) {
3864 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003865 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003866 goto done;
3867 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003868
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02003869 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
3870 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003871 err = cmd_status(sk, index, opcode,
3872 MGMT_STATUS_INVALID_INDEX);
3873 goto done;
3874 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003875 }
3876
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003877 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003878 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003879 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003880 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003881 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003882 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003883 }
3884
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003885 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003886 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003887 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003888 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003889 goto done;
3890 }
3891
Johan Hedbergbe22b542012-03-01 22:24:41 +02003892 handler = &mgmt_handlers[opcode];
3893
3894 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003895 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003896 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003897 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003898 goto done;
3899 }
3900
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003901 if (hdev)
3902 mgmt_init_hdev(sk, hdev);
3903
3904 cp = buf + sizeof(*hdr);
3905
Johan Hedbergbe22b542012-03-01 22:24:41 +02003906 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003907 if (err < 0)
3908 goto done;
3909
Johan Hedberg03811012010-12-08 00:21:06 +02003910 err = msglen;
3911
3912done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003913 if (hdev)
3914 hci_dev_put(hdev);
3915
Johan Hedberg03811012010-12-08 00:21:06 +02003916 kfree(buf);
3917 return err;
3918}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003919
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003920void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003921{
Marcel Holtmann1514b892013-10-06 08:25:01 -07003922 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003923 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003924
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003925 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003926}
3927
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003928void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003929{
Johan Hedberg5f159032012-03-02 03:13:19 +02003930 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003931
Marcel Holtmann1514b892013-10-06 08:25:01 -07003932 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003933 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003934
Johan Hedberg744cf192011-11-08 20:40:14 +02003935 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003936
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003937 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003938}
3939
Johan Hedberg229ab392013-03-15 17:06:53 -05003940static void powered_complete(struct hci_dev *hdev, u8 status)
3941{
3942 struct cmd_lookup match = { NULL, hdev };
3943
3944 BT_DBG("status 0x%02x", status);
3945
3946 hci_dev_lock(hdev);
3947
3948 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3949
3950 new_settings(hdev, match.sk);
3951
3952 hci_dev_unlock(hdev);
3953
3954 if (match.sk)
3955 sock_put(match.sk);
3956}
3957
Johan Hedberg70da6242013-03-15 17:06:51 -05003958static int powered_update_hci(struct hci_dev *hdev)
3959{
Johan Hedberg890ea892013-03-15 17:06:52 -05003960 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003961 u8 link_sec;
3962
Johan Hedberg890ea892013-03-15 17:06:52 -05003963 hci_req_init(&req, hdev);
3964
Johan Hedberg70da6242013-03-15 17:06:51 -05003965 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3966 !lmp_host_ssp_capable(hdev)) {
3967 u8 ssp = 1;
3968
Johan Hedberg890ea892013-03-15 17:06:52 -05003969 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003970 }
3971
Johan Hedbergc73eee92013-04-19 18:35:21 +03003972 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3973 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003974 struct hci_cp_write_le_host_supported cp;
3975
3976 cp.le = 1;
3977 cp.simul = lmp_le_br_capable(hdev);
3978
3979 /* Check first if we already have the right
3980 * host state (host features set)
3981 */
3982 if (cp.le != lmp_host_le_capable(hdev) ||
3983 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003984 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3985 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003986
3987 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3988 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003989 }
3990
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003991 if (lmp_le_capable(hdev)) {
3992 /* Set random address to static address if configured */
3993 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3994 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3995 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003996
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003997 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
3998 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003999 }
4000
Johan Hedberg70da6242013-03-15 17:06:51 -05004001 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4002 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004003 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4004 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004005
4006 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004007 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4008 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004009 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004010 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004011 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004012 }
4013
Johan Hedberg229ab392013-03-15 17:06:53 -05004014 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004015}
4016
Johan Hedberg744cf192011-11-08 20:40:14 +02004017int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004018{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004019 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004020 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4021 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004022 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004023
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004024 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4025 return 0;
4026
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004027 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004028 if (powered_update_hci(hdev) == 0)
4029 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004030
Johan Hedberg229ab392013-03-15 17:06:53 -05004031 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4032 &match);
4033 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004034 }
4035
Johan Hedberg229ab392013-03-15 17:06:53 -05004036 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4037 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4038
4039 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4040 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4041 zero_cod, sizeof(zero_cod), NULL);
4042
4043new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004044 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004045
4046 if (match.sk)
4047 sock_put(match.sk);
4048
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004049 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004050}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004051
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004052void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004053{
4054 struct pending_cmd *cmd;
4055 u8 status;
4056
4057 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4058 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004059 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004060
4061 if (err == -ERFKILL)
4062 status = MGMT_STATUS_RFKILLED;
4063 else
4064 status = MGMT_STATUS_FAILED;
4065
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004066 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004067
4068 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004069}
4070
Johan Hedberg744cf192011-11-08 20:40:14 +02004071int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004072{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004073 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004074 bool changed = false;
4075 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004076
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004077 if (discoverable) {
4078 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4079 changed = true;
4080 } else {
4081 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4082 changed = true;
4083 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004084
Johan Hedberged9b5f22012-02-21 20:47:06 +02004085 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004086 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02004087
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004088 if (changed)
4089 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004090
Johan Hedberg73f22f62010-12-29 16:00:25 +02004091 if (match.sk)
4092 sock_put(match.sk);
4093
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004094 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004095}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004096
Johan Hedberg744cf192011-11-08 20:40:14 +02004097int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004098{
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004099 bool changed = false;
4100 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004101
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004102 /* Nothing needed here if there's a pending command since that
4103 * commands request completion callback takes care of everything
4104 * necessary.
4105 */
4106 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
4107 return 0;
4108
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004109 if (connectable) {
4110 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4111 changed = true;
4112 } else {
4113 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4114 changed = true;
4115 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004116
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004117 if (changed)
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004118 err = new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004119
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004120 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004121}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004122
Johan Hedberg744cf192011-11-08 20:40:14 +02004123int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004124{
Johan Hedbergca69b792011-11-11 18:10:00 +02004125 u8 mgmt_err = mgmt_status(status);
4126
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004127 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004128 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004129 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004130
4131 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004132 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004133 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004134
4135 return 0;
4136}
4137
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004138int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4139 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004140{
Johan Hedberg86742e12011-11-07 23:13:38 +02004141 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004142
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004143 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004144
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004145 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004146 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004147 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004148 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004149 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004150 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004151
Johan Hedberg744cf192011-11-08 20:40:14 +02004152 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004153}
Johan Hedbergf7520542011-01-20 12:34:39 +02004154
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004155int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4156{
4157 struct mgmt_ev_new_long_term_key ev;
4158
4159 memset(&ev, 0, sizeof(ev));
4160
4161 ev.store_hint = persistent;
4162 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004163 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004164 ev.key.authenticated = key->authenticated;
4165 ev.key.enc_size = key->enc_size;
4166 ev.key.ediv = key->ediv;
4167
4168 if (key->type == HCI_SMP_LTK)
4169 ev.key.master = 1;
4170
4171 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4172 memcpy(ev.key.val, key->val, sizeof(key->val));
4173
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004174 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4175 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004176}
4177
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004178void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4179 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4180 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004181{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004182 char buf[512];
4183 struct mgmt_ev_device_connected *ev = (void *) buf;
4184 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004185
Johan Hedbergb644ba32012-01-17 21:48:47 +02004186 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004187 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004188
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004189 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004190
Johan Hedbergb644ba32012-01-17 21:48:47 +02004191 if (name_len > 0)
4192 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004193 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004194
4195 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004196 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004197 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004198
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004199 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004200
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004201 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4202 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004203}
4204
Johan Hedberg8962ee72011-01-20 12:40:27 +02004205static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4206{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004207 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004208 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004209 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004210
Johan Hedberg88c3df12012-02-09 14:27:38 +02004211 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4212 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004213
Johan Hedbergaee9b212012-02-18 15:07:59 +02004214 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004215 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004216
4217 *sk = cmd->sk;
4218 sock_hold(*sk);
4219
Johan Hedberga664b5b2011-02-19 12:06:02 -03004220 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004221}
4222
Johan Hedberg124f6e32012-02-09 13:50:12 +02004223static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004224{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004225 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004226 struct mgmt_cp_unpair_device *cp = cmd->param;
4227 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004228
4229 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004230 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4231 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004232
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004233 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4234
Johan Hedbergaee9b212012-02-18 15:07:59 +02004235 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004236
4237 mgmt_pending_remove(cmd);
4238}
4239
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004240void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4241 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004242{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004243 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004244 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004245
Johan Hedberg744cf192011-11-08 20:40:14 +02004246 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004247
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004248 bacpy(&ev.addr.bdaddr, bdaddr);
4249 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4250 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004251
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004252 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004253
4254 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004255 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004256
Johan Hedberg124f6e32012-02-09 13:50:12 +02004257 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004258 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004259}
4260
Marcel Holtmann78929242013-10-06 23:55:47 -07004261void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4262 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004263{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004264 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004265 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004266
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004267 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4268 hdev);
4269
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004270 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004271 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004272 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004273
Johan Hedberg88c3df12012-02-09 14:27:38 +02004274 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004275 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004276
Marcel Holtmann78929242013-10-06 23:55:47 -07004277 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4278 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004279
Johan Hedberga664b5b2011-02-19 12:06:02 -03004280 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004281}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004282
Marcel Holtmann445608d2013-10-06 23:55:48 -07004283void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4284 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004285{
4286 struct mgmt_ev_connect_failed ev;
4287
Johan Hedberg4c659c32011-11-07 23:13:39 +02004288 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004289 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004290 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004291
Marcel Holtmann445608d2013-10-06 23:55:48 -07004292 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004293}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004294
Johan Hedberg744cf192011-11-08 20:40:14 +02004295int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004296{
4297 struct mgmt_ev_pin_code_request ev;
4298
Johan Hedbergd8457692012-02-17 14:24:57 +02004299 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004300 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004301 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004302
Johan Hedberg744cf192011-11-08 20:40:14 +02004303 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004304 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004305}
4306
Johan Hedberg744cf192011-11-08 20:40:14 +02004307int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004308 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004309{
4310 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004311 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004312 int err;
4313
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004314 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004315 if (!cmd)
4316 return -ENOENT;
4317
Johan Hedbergd8457692012-02-17 14:24:57 +02004318 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004319 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004320
Johan Hedbergaee9b212012-02-18 15:07:59 +02004321 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004322 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004323
Johan Hedberga664b5b2011-02-19 12:06:02 -03004324 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004325
4326 return err;
4327}
4328
Johan Hedberg744cf192011-11-08 20:40:14 +02004329int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004330 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004331{
4332 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004333 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004334 int err;
4335
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004336 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004337 if (!cmd)
4338 return -ENOENT;
4339
Johan Hedbergd8457692012-02-17 14:24:57 +02004340 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004341 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004342
Johan Hedbergaee9b212012-02-18 15:07:59 +02004343 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004344 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004345
Johan Hedberga664b5b2011-02-19 12:06:02 -03004346 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004347
4348 return err;
4349}
Johan Hedberga5c29682011-02-19 12:05:57 -03004350
Johan Hedberg744cf192011-11-08 20:40:14 +02004351int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004352 u8 link_type, u8 addr_type, __le32 value,
4353 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004354{
4355 struct mgmt_ev_user_confirm_request ev;
4356
Johan Hedberg744cf192011-11-08 20:40:14 +02004357 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004358
Johan Hedberg272d90d2012-02-09 15:26:12 +02004359 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004360 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004361 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004362 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004363
Johan Hedberg744cf192011-11-08 20:40:14 +02004364 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004365 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004366}
4367
Johan Hedberg272d90d2012-02-09 15:26:12 +02004368int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004369 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004370{
4371 struct mgmt_ev_user_passkey_request ev;
4372
4373 BT_DBG("%s", hdev->name);
4374
Johan Hedberg272d90d2012-02-09 15:26:12 +02004375 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004376 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004377
4378 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004379 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004380}
4381
Brian Gix0df4c182011-11-16 13:53:13 -08004382static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004383 u8 link_type, u8 addr_type, u8 status,
4384 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004385{
4386 struct pending_cmd *cmd;
4387 struct mgmt_rp_user_confirm_reply rp;
4388 int err;
4389
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004390 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004391 if (!cmd)
4392 return -ENOENT;
4393
Johan Hedberg272d90d2012-02-09 15:26:12 +02004394 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004395 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004396 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004397 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004398
Johan Hedberga664b5b2011-02-19 12:06:02 -03004399 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004400
4401 return err;
4402}
4403
Johan Hedberg744cf192011-11-08 20:40:14 +02004404int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004405 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004406{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004407 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004408 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004409}
4410
Johan Hedberg272d90d2012-02-09 15:26:12 +02004411int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004412 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004413{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004414 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004415 status,
4416 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004417}
Johan Hedberg2a611692011-02-19 12:06:00 -03004418
Brian Gix604086b2011-11-23 08:28:33 -08004419int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004420 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004421{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004422 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004423 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004424}
4425
Johan Hedberg272d90d2012-02-09 15:26:12 +02004426int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004427 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004428{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004429 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004430 status,
4431 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004432}
4433
Johan Hedberg92a25252012-09-06 18:39:26 +03004434int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4435 u8 link_type, u8 addr_type, u32 passkey,
4436 u8 entered)
4437{
4438 struct mgmt_ev_passkey_notify ev;
4439
4440 BT_DBG("%s", hdev->name);
4441
4442 bacpy(&ev.addr.bdaddr, bdaddr);
4443 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4444 ev.passkey = __cpu_to_le32(passkey);
4445 ev.entered = entered;
4446
4447 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4448}
4449
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004450int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004451 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004452{
4453 struct mgmt_ev_auth_failed ev;
4454
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004455 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004456 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004457 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004458
Johan Hedberg744cf192011-11-08 20:40:14 +02004459 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004460}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004461
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004462int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4463{
4464 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004465 bool changed = false;
4466 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004467
4468 if (status) {
4469 u8 mgmt_err = mgmt_status(status);
4470 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004471 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004472 return 0;
4473 }
4474
Johan Hedberg47990ea2012-02-22 11:58:37 +02004475 if (test_bit(HCI_AUTH, &hdev->flags)) {
4476 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4477 changed = true;
4478 } else {
4479 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4480 changed = true;
4481 }
4482
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004483 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004484 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004485
Johan Hedberg47990ea2012-02-22 11:58:37 +02004486 if (changed)
4487 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004488
4489 if (match.sk)
4490 sock_put(match.sk);
4491
4492 return err;
4493}
4494
Johan Hedberg890ea892013-03-15 17:06:52 -05004495static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004496{
Johan Hedberg890ea892013-03-15 17:06:52 -05004497 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004498 struct hci_cp_write_eir cp;
4499
Johan Hedberg976eb202012-10-24 21:12:01 +03004500 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004501 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004502
Johan Hedbergc80da272012-02-22 15:38:48 +02004503 memset(hdev->eir, 0, sizeof(hdev->eir));
4504
Johan Hedbergcacaf522012-02-21 00:52:42 +02004505 memset(&cp, 0, sizeof(cp));
4506
Johan Hedberg890ea892013-03-15 17:06:52 -05004507 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004508}
4509
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004510int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004511{
4512 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004513 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004514 bool changed = false;
4515 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004516
4517 if (status) {
4518 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004519
4520 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004521 &hdev->dev_flags)) {
4522 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004523 err = new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004524 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004525
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004526 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4527 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004528
4529 return err;
4530 }
4531
4532 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004533 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004534 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004535 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4536 if (!changed)
4537 changed = test_and_clear_bit(HCI_HS_ENABLED,
4538 &hdev->dev_flags);
4539 else
4540 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004541 }
4542
4543 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4544
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004545 if (changed)
4546 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004547
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004548 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004549 sock_put(match.sk);
4550
Johan Hedberg890ea892013-03-15 17:06:52 -05004551 hci_req_init(&req, hdev);
4552
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004553 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004554 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004555 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004556 clear_eir(&req);
4557
4558 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004559
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004560 return err;
4561}
4562
Johan Hedberg92da6092013-03-15 17:06:55 -05004563static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004564{
4565 struct cmd_lookup *match = data;
4566
Johan Hedberg90e70452012-02-23 23:09:40 +02004567 if (match->sk == NULL) {
4568 match->sk = cmd->sk;
4569 sock_hold(match->sk);
4570 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004571}
4572
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004573int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004574 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004575{
Johan Hedberg90e70452012-02-23 23:09:40 +02004576 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4577 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004578
Johan Hedberg92da6092013-03-15 17:06:55 -05004579 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4580 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4581 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004582
4583 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004584 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4585 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004586
4587 if (match.sk)
4588 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004589
4590 return err;
4591}
4592
Johan Hedberg744cf192011-11-08 20:40:14 +02004593int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004594{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004595 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004596 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004597
Johan Hedberg13928972013-03-15 17:07:00 -05004598 if (status)
4599 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004600
4601 memset(&ev, 0, sizeof(ev));
4602 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004603 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004604
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004605 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004606 if (!cmd) {
4607 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004608
Johan Hedberg13928972013-03-15 17:07:00 -05004609 /* If this is a HCI command related to powering on the
4610 * HCI dev don't send any mgmt signals.
4611 */
4612 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4613 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004614 }
4615
Johan Hedberg13928972013-03-15 17:07:00 -05004616 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4617 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004618}
Szymon Jancc35938b2011-03-22 13:12:21 +01004619
Johan Hedberg744cf192011-11-08 20:40:14 +02004620int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004621 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004622{
4623 struct pending_cmd *cmd;
4624 int err;
4625
Johan Hedberg744cf192011-11-08 20:40:14 +02004626 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004627
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004628 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004629 if (!cmd)
4630 return -ENOENT;
4631
4632 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004633 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4634 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004635 } else {
4636 struct mgmt_rp_read_local_oob_data rp;
4637
4638 memcpy(rp.hash, hash, sizeof(rp.hash));
4639 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4640
Johan Hedberg744cf192011-11-08 20:40:14 +02004641 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004642 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4643 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004644 }
4645
4646 mgmt_pending_remove(cmd);
4647
4648 return err;
4649}
Johan Hedberge17acd42011-03-30 23:57:16 +03004650
Marcel Holtmann901801b2013-10-06 23:55:51 -07004651void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4652 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4653 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004654{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004655 char buf[512];
4656 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004657 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004658
Andre Guedes12602d02013-04-30 15:29:40 -03004659 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004660 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004661
Johan Hedberg1dc06092012-01-15 21:01:23 +02004662 /* Leave 5 bytes for a potential CoD field */
4663 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004664 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004665
Johan Hedberg1dc06092012-01-15 21:01:23 +02004666 memset(buf, 0, sizeof(buf));
4667
Johan Hedberge319d2e2012-01-15 19:51:59 +02004668 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004669 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004670 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004671 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304672 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004673 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304674 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004675
Johan Hedberg1dc06092012-01-15 21:01:23 +02004676 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004677 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004678
Johan Hedberg1dc06092012-01-15 21:01:23 +02004679 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4680 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004681 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004682
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004683 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004684 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004685
Marcel Holtmann901801b2013-10-06 23:55:51 -07004686 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004687}
Johan Hedberga88a9652011-03-30 13:18:12 +03004688
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004689void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4690 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004691{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004692 struct mgmt_ev_device_found *ev;
4693 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4694 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004695
Johan Hedbergb644ba32012-01-17 21:48:47 +02004696 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004697
Johan Hedbergb644ba32012-01-17 21:48:47 +02004698 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004699
Johan Hedbergb644ba32012-01-17 21:48:47 +02004700 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004701 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004702 ev->rssi = rssi;
4703
4704 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004705 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004706
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004707 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004708
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004709 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004710}
Johan Hedberg314b2382011-04-27 10:29:57 -04004711
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004712void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004713{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004714 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004715 struct pending_cmd *cmd;
4716
Andre Guedes343fb142011-11-22 17:14:19 -03004717 BT_DBG("%s discovering %u", hdev->name, discovering);
4718
Johan Hedberg164a6e72011-11-01 17:06:44 +02004719 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004720 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004721 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004722 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004723
4724 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004725 u8 type = hdev->discovery.type;
4726
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004727 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4728 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004729 mgmt_pending_remove(cmd);
4730 }
4731
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004732 memset(&ev, 0, sizeof(ev));
4733 ev.type = hdev->discovery.type;
4734 ev.discovering = discovering;
4735
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004736 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004737}
Antti Julku5e762442011-08-25 16:48:02 +03004738
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004739int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004740{
4741 struct pending_cmd *cmd;
4742 struct mgmt_ev_device_blocked ev;
4743
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004744 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004745
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004746 bacpy(&ev.addr.bdaddr, bdaddr);
4747 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004748
Johan Hedberg744cf192011-11-08 20:40:14 +02004749 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004750 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004751}
4752
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004753int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004754{
4755 struct pending_cmd *cmd;
4756 struct mgmt_ev_device_unblocked ev;
4757
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004758 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004759
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004760 bacpy(&ev.addr.bdaddr, bdaddr);
4761 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004762
Johan Hedberg744cf192011-11-08 20:40:14 +02004763 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004764 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004765}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004766
4767static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4768{
4769 BT_DBG("%s status %u", hdev->name, status);
4770
4771 /* Clear the advertising mgmt setting if we failed to re-enable it */
4772 if (status) {
4773 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004774 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004775 }
4776}
4777
4778void mgmt_reenable_advertising(struct hci_dev *hdev)
4779{
4780 struct hci_request req;
4781
Marcel Holtmannb145edc2013-10-10 09:47:54 -07004782 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07004783 return;
4784
4785 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4786 return;
4787
4788 hci_req_init(&req, hdev);
4789 enable_advertising(&req);
4790
4791 /* If this fails we have no option but to let user space know
4792 * that we've disabled advertising.
4793 */
4794 if (hci_req_run(&req, adv_enable_complete) < 0) {
4795 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004796 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004797 }
4798}