blob: 0bad451e5a90626e25ce3be1e4c4e6f5b5b273d6 [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 Hedberg84bde9d6c2012-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 Hedberg84bde9d6c2012-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) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003643 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3644 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3645 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3646 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3647 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3648 }
3649
3650 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3651
3652 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3653 if (err < 0)
3654 goto unlock;
3655
3656 err = new_settings(hdev, sk);
3657 goto unlock;
3658 }
3659
3660 /* Reject disabling when powered on */
3661 if (!cp->val) {
3662 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3663 MGMT_STATUS_REJECTED);
3664 goto unlock;
3665 }
3666
3667 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3668 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3669 MGMT_STATUS_BUSY);
3670 goto unlock;
3671 }
3672
3673 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3674 if (!cmd) {
3675 err = -ENOMEM;
3676 goto unlock;
3677 }
3678
3679 /* We need to flip the bit already here so that hci_update_ad
3680 * generates the correct flags.
3681 */
3682 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3683
3684 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003685
3686 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3687 set_bredr_scan(&req);
3688
Johan Hedberg0663ca22013-10-02 13:43:14 +03003689 hci_update_ad(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003690
Johan Hedberg0663ca22013-10-02 13:43:14 +03003691 err = hci_req_run(&req, set_bredr_complete);
3692 if (err < 0)
3693 mgmt_pending_remove(cmd);
3694
3695unlock:
3696 hci_dev_unlock(hdev);
3697 return err;
3698}
3699
Johan Hedberg3f706b72013-01-20 14:27:16 +02003700static bool ltk_is_valid(struct mgmt_ltk_info *key)
3701{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003702 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3703 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003704 if (key->master != 0x00 && key->master != 0x01)
3705 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003706 if (!bdaddr_type_is_le(key->addr.type))
3707 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003708 return true;
3709}
3710
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003711static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003712 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003713{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003714 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3715 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003716 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003717
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003718 BT_DBG("request for %s", hdev->name);
3719
3720 if (!lmp_le_capable(hdev))
3721 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3722 MGMT_STATUS_NOT_SUPPORTED);
3723
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003724 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003725
3726 expected_len = sizeof(*cp) + key_count *
3727 sizeof(struct mgmt_ltk_info);
3728 if (expected_len != len) {
3729 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003730 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003731 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003732 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003733 }
3734
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003735 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003736
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003737 for (i = 0; i < key_count; i++) {
3738 struct mgmt_ltk_info *key = &cp->keys[i];
3739
Johan Hedberg3f706b72013-01-20 14:27:16 +02003740 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003741 return cmd_status(sk, hdev->id,
3742 MGMT_OP_LOAD_LONG_TERM_KEYS,
3743 MGMT_STATUS_INVALID_PARAMS);
3744 }
3745
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003746 hci_dev_lock(hdev);
3747
3748 hci_smp_ltks_clear(hdev);
3749
3750 for (i = 0; i < key_count; i++) {
3751 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003752 u8 type, addr_type;
3753
3754 if (key->addr.type == BDADDR_LE_PUBLIC)
3755 addr_type = ADDR_LE_DEV_PUBLIC;
3756 else
3757 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003758
3759 if (key->master)
3760 type = HCI_SMP_LTK;
3761 else
3762 type = HCI_SMP_LTK_SLAVE;
3763
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003764 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003765 type, 0, key->authenticated, key->val,
3766 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003767 }
3768
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003769 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3770 NULL, 0);
3771
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003772 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003773
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003774 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003775}
3776
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003777static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003778 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3779 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003780 bool var_len;
3781 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003782} mgmt_handlers[] = {
3783 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003784 { read_version, false, MGMT_READ_VERSION_SIZE },
3785 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3786 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3787 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3788 { set_powered, false, MGMT_SETTING_SIZE },
3789 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3790 { set_connectable, false, MGMT_SETTING_SIZE },
3791 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3792 { set_pairable, false, MGMT_SETTING_SIZE },
3793 { set_link_security, false, MGMT_SETTING_SIZE },
3794 { set_ssp, false, MGMT_SETTING_SIZE },
3795 { set_hs, false, MGMT_SETTING_SIZE },
3796 { set_le, false, MGMT_SETTING_SIZE },
3797 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3798 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3799 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3800 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3801 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3802 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3803 { disconnect, false, MGMT_DISCONNECT_SIZE },
3804 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3805 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3806 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3807 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3808 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3809 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3810 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3811 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3812 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3813 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3814 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3815 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3816 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3817 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3818 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3819 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3820 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3821 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3822 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003823 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003824 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003825 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003826 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003827 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003828};
3829
3830
Johan Hedberg03811012010-12-08 00:21:06 +02003831int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3832{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003833 void *buf;
3834 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003835 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003836 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003837 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003838 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003839 int err;
3840
3841 BT_DBG("got %zu bytes", msglen);
3842
3843 if (msglen < sizeof(*hdr))
3844 return -EINVAL;
3845
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003846 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003847 if (!buf)
3848 return -ENOMEM;
3849
3850 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3851 err = -EFAULT;
3852 goto done;
3853 }
3854
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003855 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003856 opcode = __le16_to_cpu(hdr->opcode);
3857 index = __le16_to_cpu(hdr->index);
3858 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003859
3860 if (len != msglen - sizeof(*hdr)) {
3861 err = -EINVAL;
3862 goto done;
3863 }
3864
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003865 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003866 hdev = hci_dev_get(index);
3867 if (!hdev) {
3868 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003869 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003870 goto done;
3871 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003872
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02003873 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
3874 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003875 err = cmd_status(sk, index, opcode,
3876 MGMT_STATUS_INVALID_INDEX);
3877 goto done;
3878 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003879 }
3880
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003881 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003882 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003883 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003884 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003885 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003886 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003887 }
3888
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003889 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003890 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003891 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003892 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003893 goto done;
3894 }
3895
Johan Hedbergbe22b542012-03-01 22:24:41 +02003896 handler = &mgmt_handlers[opcode];
3897
3898 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003899 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003900 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003901 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003902 goto done;
3903 }
3904
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003905 if (hdev)
3906 mgmt_init_hdev(sk, hdev);
3907
3908 cp = buf + sizeof(*hdr);
3909
Johan Hedbergbe22b542012-03-01 22:24:41 +02003910 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003911 if (err < 0)
3912 goto done;
3913
Johan Hedberg03811012010-12-08 00:21:06 +02003914 err = msglen;
3915
3916done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003917 if (hdev)
3918 hci_dev_put(hdev);
3919
Johan Hedberg03811012010-12-08 00:21:06 +02003920 kfree(buf);
3921 return err;
3922}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003923
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003924void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003925{
Marcel Holtmann1514b892013-10-06 08:25:01 -07003926 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003927 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003928
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003929 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003930}
3931
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003932void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003933{
Johan Hedberg5f159032012-03-02 03:13:19 +02003934 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003935
Marcel Holtmann1514b892013-10-06 08:25:01 -07003936 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003937 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003938
Johan Hedberg744cf192011-11-08 20:40:14 +02003939 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003940
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003941 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003942}
3943
Johan Hedberg229ab392013-03-15 17:06:53 -05003944static void powered_complete(struct hci_dev *hdev, u8 status)
3945{
3946 struct cmd_lookup match = { NULL, hdev };
3947
3948 BT_DBG("status 0x%02x", status);
3949
3950 hci_dev_lock(hdev);
3951
3952 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3953
3954 new_settings(hdev, match.sk);
3955
3956 hci_dev_unlock(hdev);
3957
3958 if (match.sk)
3959 sock_put(match.sk);
3960}
3961
Johan Hedberg70da6242013-03-15 17:06:51 -05003962static int powered_update_hci(struct hci_dev *hdev)
3963{
Johan Hedberg890ea892013-03-15 17:06:52 -05003964 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003965 u8 link_sec;
3966
Johan Hedberg890ea892013-03-15 17:06:52 -05003967 hci_req_init(&req, hdev);
3968
Johan Hedberg70da6242013-03-15 17:06:51 -05003969 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3970 !lmp_host_ssp_capable(hdev)) {
3971 u8 ssp = 1;
3972
Johan Hedberg890ea892013-03-15 17:06:52 -05003973 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003974 }
3975
Johan Hedbergc73eee92013-04-19 18:35:21 +03003976 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3977 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003978 struct hci_cp_write_le_host_supported cp;
3979
3980 cp.le = 1;
3981 cp.simul = lmp_le_br_capable(hdev);
3982
3983 /* Check first if we already have the right
3984 * host state (host features set)
3985 */
3986 if (cp.le != lmp_host_le_capable(hdev) ||
3987 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003988 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3989 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003990
3991 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3992 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003993 }
3994
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003995 if (lmp_le_capable(hdev)) {
3996 /* Set random address to static address if configured */
3997 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3998 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3999 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004000
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004001 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4002 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004003 }
4004
Johan Hedberg70da6242013-03-15 17:06:51 -05004005 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4006 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004007 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4008 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004009
4010 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004011 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4012 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004013 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004014 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004015 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004016 }
4017
Johan Hedberg229ab392013-03-15 17:06:53 -05004018 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004019}
4020
Johan Hedberg744cf192011-11-08 20:40:14 +02004021int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004022{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004023 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004024 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4025 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004026 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004027
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004028 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4029 return 0;
4030
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004031 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004032 if (powered_update_hci(hdev) == 0)
4033 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004034
Johan Hedberg229ab392013-03-15 17:06:53 -05004035 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4036 &match);
4037 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004038 }
4039
Johan Hedberg229ab392013-03-15 17:06:53 -05004040 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4041 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4042
4043 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4044 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4045 zero_cod, sizeof(zero_cod), NULL);
4046
4047new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004048 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004049
4050 if (match.sk)
4051 sock_put(match.sk);
4052
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004053 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004054}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004055
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004056void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004057{
4058 struct pending_cmd *cmd;
4059 u8 status;
4060
4061 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4062 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004063 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004064
4065 if (err == -ERFKILL)
4066 status = MGMT_STATUS_RFKILLED;
4067 else
4068 status = MGMT_STATUS_FAILED;
4069
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004070 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004071
4072 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004073}
4074
Johan Hedberg744cf192011-11-08 20:40:14 +02004075int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004076{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004077 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004078 bool changed = false;
4079 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004080
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004081 if (discoverable) {
4082 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4083 changed = true;
4084 } else {
4085 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4086 changed = true;
4087 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004088
Johan Hedberged9b5f22012-02-21 20:47:06 +02004089 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004090 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02004091
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004092 if (changed)
4093 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004094
Johan Hedberg73f22f62010-12-29 16:00:25 +02004095 if (match.sk)
4096 sock_put(match.sk);
4097
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004098 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004099}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004100
Johan Hedberg744cf192011-11-08 20:40:14 +02004101int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004102{
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004103 bool changed = false;
4104 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004105
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004106 /* Nothing needed here if there's a pending command since that
4107 * commands request completion callback takes care of everything
4108 * necessary.
4109 */
4110 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
4111 return 0;
4112
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004113 if (connectable) {
4114 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4115 changed = true;
4116 } else {
4117 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4118 changed = true;
4119 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004120
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004121 if (changed)
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004122 err = new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004123
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004124 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004125}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004126
Johan Hedberg744cf192011-11-08 20:40:14 +02004127int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004128{
Johan Hedbergca69b792011-11-11 18:10:00 +02004129 u8 mgmt_err = mgmt_status(status);
4130
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004131 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004132 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004133 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004134
4135 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004136 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004137 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004138
4139 return 0;
4140}
4141
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004142int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4143 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004144{
Johan Hedberg86742e12011-11-07 23:13:38 +02004145 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004146
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004147 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004148
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004149 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004150 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004151 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004152 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004153 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004154 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004155
Johan Hedberg744cf192011-11-08 20:40:14 +02004156 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004157}
Johan Hedbergf7520542011-01-20 12:34:39 +02004158
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004159int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4160{
4161 struct mgmt_ev_new_long_term_key ev;
4162
4163 memset(&ev, 0, sizeof(ev));
4164
4165 ev.store_hint = persistent;
4166 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004167 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004168 ev.key.authenticated = key->authenticated;
4169 ev.key.enc_size = key->enc_size;
4170 ev.key.ediv = key->ediv;
4171
4172 if (key->type == HCI_SMP_LTK)
4173 ev.key.master = 1;
4174
4175 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4176 memcpy(ev.key.val, key->val, sizeof(key->val));
4177
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004178 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4179 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004180}
4181
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004182void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4183 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4184 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004185{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004186 char buf[512];
4187 struct mgmt_ev_device_connected *ev = (void *) buf;
4188 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004189
Johan Hedbergb644ba32012-01-17 21:48:47 +02004190 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004191 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004192
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004193 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004194
Johan Hedbergb644ba32012-01-17 21:48:47 +02004195 if (name_len > 0)
4196 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004197 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004198
4199 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004200 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004201 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004202
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004203 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004204
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004205 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4206 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004207}
4208
Johan Hedberg8962ee72011-01-20 12:40:27 +02004209static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4210{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004211 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004212 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004213 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004214
Johan Hedberg88c3df12012-02-09 14:27:38 +02004215 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4216 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004217
Johan Hedbergaee9b212012-02-18 15:07:59 +02004218 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004219 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004220
4221 *sk = cmd->sk;
4222 sock_hold(*sk);
4223
Johan Hedberga664b5b2011-02-19 12:06:02 -03004224 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004225}
4226
Johan Hedberg124f6e32012-02-09 13:50:12 +02004227static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004228{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004229 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004230 struct mgmt_cp_unpair_device *cp = cmd->param;
4231 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004232
4233 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004234 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4235 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004236
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004237 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4238
Johan Hedbergaee9b212012-02-18 15:07:59 +02004239 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004240
4241 mgmt_pending_remove(cmd);
4242}
4243
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004244void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4245 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004246{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004247 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004248 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004249
Johan Hedberg744cf192011-11-08 20:40:14 +02004250 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004251
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004252 bacpy(&ev.addr.bdaddr, bdaddr);
4253 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4254 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004255
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004256 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004257
4258 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004259 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004260
Johan Hedberg124f6e32012-02-09 13:50:12 +02004261 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004262 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004263}
4264
Marcel Holtmann78929242013-10-06 23:55:47 -07004265void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4266 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004267{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004268 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004269 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004270
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004271 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4272 hdev);
4273
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004274 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004275 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004276 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004277
Johan Hedberg88c3df12012-02-09 14:27:38 +02004278 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004279 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004280
Marcel Holtmann78929242013-10-06 23:55:47 -07004281 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4282 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004283
Johan Hedberga664b5b2011-02-19 12:06:02 -03004284 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004285}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004286
Marcel Holtmann445608d2013-10-06 23:55:48 -07004287void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4288 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004289{
4290 struct mgmt_ev_connect_failed ev;
4291
Johan Hedberg4c659c32011-11-07 23:13:39 +02004292 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004293 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004294 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004295
Marcel Holtmann445608d2013-10-06 23:55:48 -07004296 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004297}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004298
Johan Hedberg744cf192011-11-08 20:40:14 +02004299int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004300{
4301 struct mgmt_ev_pin_code_request ev;
4302
Johan Hedbergd8457692012-02-17 14:24:57 +02004303 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004304 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004305 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004306
Johan Hedberg744cf192011-11-08 20:40:14 +02004307 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004308 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004309}
4310
Johan Hedberg744cf192011-11-08 20:40:14 +02004311int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004312 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004313{
4314 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004315 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004316 int err;
4317
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004318 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004319 if (!cmd)
4320 return -ENOENT;
4321
Johan Hedbergd8457692012-02-17 14:24:57 +02004322 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004323 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004324
Johan Hedbergaee9b212012-02-18 15:07:59 +02004325 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004326 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004327
Johan Hedberga664b5b2011-02-19 12:06:02 -03004328 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004329
4330 return err;
4331}
4332
Johan Hedberg744cf192011-11-08 20:40:14 +02004333int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004334 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004335{
4336 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004337 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004338 int err;
4339
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004340 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004341 if (!cmd)
4342 return -ENOENT;
4343
Johan Hedbergd8457692012-02-17 14:24:57 +02004344 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004345 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004346
Johan Hedbergaee9b212012-02-18 15:07:59 +02004347 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004348 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004349
Johan Hedberga664b5b2011-02-19 12:06:02 -03004350 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004351
4352 return err;
4353}
Johan Hedberga5c29682011-02-19 12:05:57 -03004354
Johan Hedberg744cf192011-11-08 20:40:14 +02004355int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004356 u8 link_type, u8 addr_type, __le32 value,
4357 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004358{
4359 struct mgmt_ev_user_confirm_request ev;
4360
Johan Hedberg744cf192011-11-08 20:40:14 +02004361 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004362
Johan Hedberg272d90d2012-02-09 15:26:12 +02004363 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004364 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004365 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004366 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004367
Johan Hedberg744cf192011-11-08 20:40:14 +02004368 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004369 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004370}
4371
Johan Hedberg272d90d2012-02-09 15:26:12 +02004372int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004373 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004374{
4375 struct mgmt_ev_user_passkey_request ev;
4376
4377 BT_DBG("%s", hdev->name);
4378
Johan Hedberg272d90d2012-02-09 15:26:12 +02004379 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004380 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004381
4382 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004383 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004384}
4385
Brian Gix0df4c182011-11-16 13:53:13 -08004386static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004387 u8 link_type, u8 addr_type, u8 status,
4388 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004389{
4390 struct pending_cmd *cmd;
4391 struct mgmt_rp_user_confirm_reply rp;
4392 int err;
4393
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004394 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004395 if (!cmd)
4396 return -ENOENT;
4397
Johan Hedberg272d90d2012-02-09 15:26:12 +02004398 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004399 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004400 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004401 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004402
Johan Hedberga664b5b2011-02-19 12:06:02 -03004403 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004404
4405 return err;
4406}
4407
Johan Hedberg744cf192011-11-08 20:40:14 +02004408int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004409 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004410{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004411 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004412 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004413}
4414
Johan Hedberg272d90d2012-02-09 15:26:12 +02004415int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004416 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004417{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004418 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004419 status,
4420 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004421}
Johan Hedberg2a611692011-02-19 12:06:00 -03004422
Brian Gix604086b2011-11-23 08:28:33 -08004423int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004424 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004425{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004426 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004427 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004428}
4429
Johan Hedberg272d90d2012-02-09 15:26:12 +02004430int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004431 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004432{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004433 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004434 status,
4435 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004436}
4437
Johan Hedberg92a25252012-09-06 18:39:26 +03004438int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4439 u8 link_type, u8 addr_type, u32 passkey,
4440 u8 entered)
4441{
4442 struct mgmt_ev_passkey_notify ev;
4443
4444 BT_DBG("%s", hdev->name);
4445
4446 bacpy(&ev.addr.bdaddr, bdaddr);
4447 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4448 ev.passkey = __cpu_to_le32(passkey);
4449 ev.entered = entered;
4450
4451 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4452}
4453
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004454int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004455 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004456{
4457 struct mgmt_ev_auth_failed ev;
4458
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004459 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004460 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004461 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004462
Johan Hedberg744cf192011-11-08 20:40:14 +02004463 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004464}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004465
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004466int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4467{
4468 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004469 bool changed = false;
4470 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004471
4472 if (status) {
4473 u8 mgmt_err = mgmt_status(status);
4474 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004475 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004476 return 0;
4477 }
4478
Johan Hedberg47990ea2012-02-22 11:58:37 +02004479 if (test_bit(HCI_AUTH, &hdev->flags)) {
4480 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4481 changed = true;
4482 } else {
4483 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4484 changed = true;
4485 }
4486
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004487 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004488 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004489
Johan Hedberg47990ea2012-02-22 11:58:37 +02004490 if (changed)
4491 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004492
4493 if (match.sk)
4494 sock_put(match.sk);
4495
4496 return err;
4497}
4498
Johan Hedberg890ea892013-03-15 17:06:52 -05004499static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004500{
Johan Hedberg890ea892013-03-15 17:06:52 -05004501 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004502 struct hci_cp_write_eir cp;
4503
Johan Hedberg976eb202012-10-24 21:12:01 +03004504 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004505 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004506
Johan Hedbergc80da272012-02-22 15:38:48 +02004507 memset(hdev->eir, 0, sizeof(hdev->eir));
4508
Johan Hedbergcacaf522012-02-21 00:52:42 +02004509 memset(&cp, 0, sizeof(cp));
4510
Johan Hedberg890ea892013-03-15 17:06:52 -05004511 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004512}
4513
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004514int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004515{
4516 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004517 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004518 bool changed = false;
4519 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004520
4521 if (status) {
4522 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004523
4524 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004525 &hdev->dev_flags)) {
4526 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004527 err = new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004528 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004529
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004530 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4531 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004532
4533 return err;
4534 }
4535
4536 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004537 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004538 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004539 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4540 if (!changed)
4541 changed = test_and_clear_bit(HCI_HS_ENABLED,
4542 &hdev->dev_flags);
4543 else
4544 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004545 }
4546
4547 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4548
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004549 if (changed)
4550 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004551
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004552 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004553 sock_put(match.sk);
4554
Johan Hedberg890ea892013-03-15 17:06:52 -05004555 hci_req_init(&req, hdev);
4556
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004557 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004558 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004559 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004560 clear_eir(&req);
4561
4562 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004563
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004564 return err;
4565}
4566
Johan Hedberg92da6092013-03-15 17:06:55 -05004567static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004568{
4569 struct cmd_lookup *match = data;
4570
Johan Hedberg90e70452012-02-23 23:09:40 +02004571 if (match->sk == NULL) {
4572 match->sk = cmd->sk;
4573 sock_hold(match->sk);
4574 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004575}
4576
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004577int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004578 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004579{
Johan Hedberg90e70452012-02-23 23:09:40 +02004580 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4581 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004582
Johan Hedberg92da6092013-03-15 17:06:55 -05004583 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4584 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4585 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004586
4587 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004588 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4589 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004590
4591 if (match.sk)
4592 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004593
4594 return err;
4595}
4596
Johan Hedberg744cf192011-11-08 20:40:14 +02004597int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004598{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004599 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004600 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004601
Johan Hedberg13928972013-03-15 17:07:00 -05004602 if (status)
4603 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004604
4605 memset(&ev, 0, sizeof(ev));
4606 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004607 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004608
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004609 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004610 if (!cmd) {
4611 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004612
Johan Hedberg13928972013-03-15 17:07:00 -05004613 /* If this is a HCI command related to powering on the
4614 * HCI dev don't send any mgmt signals.
4615 */
4616 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4617 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004618 }
4619
Johan Hedberg13928972013-03-15 17:07:00 -05004620 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4621 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004622}
Szymon Jancc35938b2011-03-22 13:12:21 +01004623
Johan Hedberg744cf192011-11-08 20:40:14 +02004624int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004625 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004626{
4627 struct pending_cmd *cmd;
4628 int err;
4629
Johan Hedberg744cf192011-11-08 20:40:14 +02004630 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004631
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004632 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004633 if (!cmd)
4634 return -ENOENT;
4635
4636 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004637 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4638 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004639 } else {
4640 struct mgmt_rp_read_local_oob_data rp;
4641
4642 memcpy(rp.hash, hash, sizeof(rp.hash));
4643 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4644
Johan Hedberg744cf192011-11-08 20:40:14 +02004645 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004646 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4647 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004648 }
4649
4650 mgmt_pending_remove(cmd);
4651
4652 return err;
4653}
Johan Hedberge17acd42011-03-30 23:57:16 +03004654
Marcel Holtmann901801b2013-10-06 23:55:51 -07004655void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4656 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4657 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004658{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004659 char buf[512];
4660 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004661 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004662
Andre Guedes12602d02013-04-30 15:29:40 -03004663 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004664 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004665
Johan Hedberg1dc06092012-01-15 21:01:23 +02004666 /* Leave 5 bytes for a potential CoD field */
4667 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004668 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004669
Johan Hedberg1dc06092012-01-15 21:01:23 +02004670 memset(buf, 0, sizeof(buf));
4671
Johan Hedberge319d2e2012-01-15 19:51:59 +02004672 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004673 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004674 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004675 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304676 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004677 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304678 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004679
Johan Hedberg1dc06092012-01-15 21:01:23 +02004680 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004681 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004682
Johan Hedberg1dc06092012-01-15 21:01:23 +02004683 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4684 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004685 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004686
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004687 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004688 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004689
Marcel Holtmann901801b2013-10-06 23:55:51 -07004690 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004691}
Johan Hedberga88a9652011-03-30 13:18:12 +03004692
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004693void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4694 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004695{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004696 struct mgmt_ev_device_found *ev;
4697 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4698 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004699
Johan Hedbergb644ba32012-01-17 21:48:47 +02004700 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004701
Johan Hedbergb644ba32012-01-17 21:48:47 +02004702 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004703
Johan Hedbergb644ba32012-01-17 21:48:47 +02004704 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004705 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004706 ev->rssi = rssi;
4707
4708 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004709 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004710
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004711 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004712
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004713 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004714}
Johan Hedberg314b2382011-04-27 10:29:57 -04004715
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004716void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004717{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004718 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004719 struct pending_cmd *cmd;
4720
Andre Guedes343fb142011-11-22 17:14:19 -03004721 BT_DBG("%s discovering %u", hdev->name, discovering);
4722
Johan Hedberg164a6e72011-11-01 17:06:44 +02004723 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004724 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004725 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004726 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004727
4728 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004729 u8 type = hdev->discovery.type;
4730
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004731 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4732 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004733 mgmt_pending_remove(cmd);
4734 }
4735
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004736 memset(&ev, 0, sizeof(ev));
4737 ev.type = hdev->discovery.type;
4738 ev.discovering = discovering;
4739
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004740 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004741}
Antti Julku5e762442011-08-25 16:48:02 +03004742
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004743int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004744{
4745 struct pending_cmd *cmd;
4746 struct mgmt_ev_device_blocked ev;
4747
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004748 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004749
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004750 bacpy(&ev.addr.bdaddr, bdaddr);
4751 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004752
Johan Hedberg744cf192011-11-08 20:40:14 +02004753 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004754 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004755}
4756
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004757int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004758{
4759 struct pending_cmd *cmd;
4760 struct mgmt_ev_device_unblocked ev;
4761
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004762 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004763
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004764 bacpy(&ev.addr.bdaddr, bdaddr);
4765 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004766
Johan Hedberg744cf192011-11-08 20:40:14 +02004767 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004768 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004769}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004770
4771static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4772{
4773 BT_DBG("%s status %u", hdev->name, status);
4774
4775 /* Clear the advertising mgmt setting if we failed to re-enable it */
4776 if (status) {
4777 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004778 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004779 }
4780}
4781
4782void mgmt_reenable_advertising(struct hci_dev *hdev)
4783{
4784 struct hci_request req;
4785
Marcel Holtmannb145edc2013-10-10 09:47:54 -07004786 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07004787 return;
4788
4789 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4790 return;
4791
4792 hci_req_init(&req, hdev);
4793 enable_advertising(&req);
4794
4795 /* If this fails we have no option but to let user space know
4796 * that we've disabled advertising.
4797 */
4798 if (hci_req_run(&req, adv_enable_complete) < 0) {
4799 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004800 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004801 }
4802}