blob: 70bef3d5db579a741e1d2fbd11e39657245ae25f [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 Holtmann404566442014-01-28 15:39:01 -080037#define MGMT_REVISION 5
Johan Hedberg02d98122010-12-13 21:07:04 +020038
Johan Hedberge70bb2e2012-02-13 16:59:33 +020039static const u16 mgmt_commands[] = {
40 MGMT_OP_READ_INDEX_LIST,
41 MGMT_OP_READ_INFO,
42 MGMT_OP_SET_POWERED,
43 MGMT_OP_SET_DISCOVERABLE,
44 MGMT_OP_SET_CONNECTABLE,
45 MGMT_OP_SET_FAST_CONNECTABLE,
46 MGMT_OP_SET_PAIRABLE,
47 MGMT_OP_SET_LINK_SECURITY,
48 MGMT_OP_SET_SSP,
49 MGMT_OP_SET_HS,
50 MGMT_OP_SET_LE,
51 MGMT_OP_SET_DEV_CLASS,
52 MGMT_OP_SET_LOCAL_NAME,
53 MGMT_OP_ADD_UUID,
54 MGMT_OP_REMOVE_UUID,
55 MGMT_OP_LOAD_LINK_KEYS,
56 MGMT_OP_LOAD_LONG_TERM_KEYS,
57 MGMT_OP_DISCONNECT,
58 MGMT_OP_GET_CONNECTIONS,
59 MGMT_OP_PIN_CODE_REPLY,
60 MGMT_OP_PIN_CODE_NEG_REPLY,
61 MGMT_OP_SET_IO_CAPABILITY,
62 MGMT_OP_PAIR_DEVICE,
63 MGMT_OP_CANCEL_PAIR_DEVICE,
64 MGMT_OP_UNPAIR_DEVICE,
65 MGMT_OP_USER_CONFIRM_REPLY,
66 MGMT_OP_USER_CONFIRM_NEG_REPLY,
67 MGMT_OP_USER_PASSKEY_REPLY,
68 MGMT_OP_USER_PASSKEY_NEG_REPLY,
69 MGMT_OP_READ_LOCAL_OOB_DATA,
70 MGMT_OP_ADD_REMOTE_OOB_DATA,
71 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
72 MGMT_OP_START_DISCOVERY,
73 MGMT_OP_STOP_DISCOVERY,
74 MGMT_OP_CONFIRM_NAME,
75 MGMT_OP_BLOCK_DEVICE,
76 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070077 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030078 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030079 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070080 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070081 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080082 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080083 MGMT_OP_SET_DEBUG_KEYS,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020084};
85
86static const u16 mgmt_events[] = {
87 MGMT_EV_CONTROLLER_ERROR,
88 MGMT_EV_INDEX_ADDED,
89 MGMT_EV_INDEX_REMOVED,
90 MGMT_EV_NEW_SETTINGS,
91 MGMT_EV_CLASS_OF_DEV_CHANGED,
92 MGMT_EV_LOCAL_NAME_CHANGED,
93 MGMT_EV_NEW_LINK_KEY,
94 MGMT_EV_NEW_LONG_TERM_KEY,
95 MGMT_EV_DEVICE_CONNECTED,
96 MGMT_EV_DEVICE_DISCONNECTED,
97 MGMT_EV_CONNECT_FAILED,
98 MGMT_EV_PIN_CODE_REQUEST,
99 MGMT_EV_USER_CONFIRM_REQUEST,
100 MGMT_EV_USER_PASSKEY_REQUEST,
101 MGMT_EV_AUTH_FAILED,
102 MGMT_EV_DEVICE_FOUND,
103 MGMT_EV_DISCOVERING,
104 MGMT_EV_DEVICE_BLOCKED,
105 MGMT_EV_DEVICE_UNBLOCKED,
106 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300107 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200108};
109
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800110#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200111
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200112#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
113 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
114
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200115struct pending_cmd {
116 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200117 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200118 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100119 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200120 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300121 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200122};
123
Johan Hedbergca69b792011-11-11 18:10:00 +0200124/* HCI to MGMT error code conversion table */
125static u8 mgmt_status_table[] = {
126 MGMT_STATUS_SUCCESS,
127 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
128 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
129 MGMT_STATUS_FAILED, /* Hardware Failure */
130 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
131 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200132 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200133 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
134 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
135 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
136 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
137 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
138 MGMT_STATUS_BUSY, /* Command Disallowed */
139 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
140 MGMT_STATUS_REJECTED, /* Rejected Security */
141 MGMT_STATUS_REJECTED, /* Rejected Personal */
142 MGMT_STATUS_TIMEOUT, /* Host Timeout */
143 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
144 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
145 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
146 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
147 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
148 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
149 MGMT_STATUS_BUSY, /* Repeated Attempts */
150 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
151 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
153 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
154 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
155 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
156 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
157 MGMT_STATUS_FAILED, /* Unspecified Error */
158 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
159 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
160 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
161 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
162 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
163 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
164 MGMT_STATUS_FAILED, /* Unit Link Key Used */
165 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
166 MGMT_STATUS_TIMEOUT, /* Instant Passed */
167 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
168 MGMT_STATUS_FAILED, /* Transaction Collision */
169 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
170 MGMT_STATUS_REJECTED, /* QoS Rejected */
171 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
172 MGMT_STATUS_REJECTED, /* Insufficient Security */
173 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
174 MGMT_STATUS_BUSY, /* Role Switch Pending */
175 MGMT_STATUS_FAILED, /* Slot Violation */
176 MGMT_STATUS_FAILED, /* Role Switch Failed */
177 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
178 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
179 MGMT_STATUS_BUSY, /* Host Busy Pairing */
180 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
181 MGMT_STATUS_BUSY, /* Controller Busy */
182 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
183 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
184 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
185 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
186 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
187};
188
189static u8 mgmt_status(u8 hci_status)
190{
191 if (hci_status < ARRAY_SIZE(mgmt_status_table))
192 return mgmt_status_table[hci_status];
193
194 return MGMT_STATUS_FAILED;
195}
196
Szymon Janc4e51eae2011-02-25 19:05:48 +0100197static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200198{
199 struct sk_buff *skb;
200 struct mgmt_hdr *hdr;
201 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300202 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200203
Szymon Janc34eb5252011-02-28 14:10:08 +0100204 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200205
Andre Guedes790eff42012-06-07 19:05:46 -0300206 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200207 if (!skb)
208 return -ENOMEM;
209
210 hdr = (void *) skb_put(skb, sizeof(*hdr));
211
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530212 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100213 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200214 hdr->len = cpu_to_le16(sizeof(*ev));
215
216 ev = (void *) skb_put(skb, sizeof(*ev));
217 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200218 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200219
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300220 err = sock_queue_rcv_skb(sk, skb);
221 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200222 kfree_skb(skb);
223
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300224 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200225}
226
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200227static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300228 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200229{
230 struct sk_buff *skb;
231 struct mgmt_hdr *hdr;
232 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200234
235 BT_DBG("sock %p", sk);
236
Andre Guedes790eff42012-06-07 19:05:46 -0300237 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200238 if (!skb)
239 return -ENOMEM;
240
241 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200242
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530243 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100244 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200245 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200246
Johan Hedberga38528f2011-01-22 06:46:43 +0200247 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200248 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200249 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100250
251 if (rp)
252 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200253
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300254 err = sock_queue_rcv_skb(sk, skb);
255 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200256 kfree_skb(skb);
257
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100258 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200259}
260
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300261static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
262 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200263{
264 struct mgmt_rp_read_version rp;
265
266 BT_DBG("sock %p", sk);
267
268 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200269 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200270
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200271 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300272 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200273}
274
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300275static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
276 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200277{
278 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200279 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
280 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200281 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200282 size_t rp_size;
283 int i, err;
284
285 BT_DBG("sock %p", sk);
286
287 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
288
289 rp = kmalloc(rp_size, GFP_KERNEL);
290 if (!rp)
291 return -ENOMEM;
292
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200293 rp->num_commands = __constant_cpu_to_le16(num_commands);
294 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200295
296 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
297 put_unaligned_le16(mgmt_commands[i], opcode);
298
299 for (i = 0; i < num_events; i++, opcode++)
300 put_unaligned_le16(mgmt_events[i], opcode);
301
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200302 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300303 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200304 kfree(rp);
305
306 return err;
307}
308
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300309static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
310 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200311{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200312 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200313 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200314 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200315 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300316 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200317
318 BT_DBG("sock %p", sk);
319
320 read_lock(&hci_dev_list_lock);
321
322 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300323 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700324 if (d->dev_type == HCI_BREDR)
325 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200326 }
327
Johan Hedberga38528f2011-01-22 06:46:43 +0200328 rp_len = sizeof(*rp) + (2 * count);
329 rp = kmalloc(rp_len, GFP_ATOMIC);
330 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100331 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200332 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100333 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200334
Johan Hedberg476e44c2012-10-19 20:10:46 +0300335 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200336 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200337 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200338 continue;
339
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700340 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
341 continue;
342
Marcel Holtmann1514b892013-10-06 08:25:01 -0700343 if (d->dev_type == HCI_BREDR) {
344 rp->index[count++] = cpu_to_le16(d->id);
345 BT_DBG("Added hci%u", d->id);
346 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200347 }
348
Johan Hedberg476e44c2012-10-19 20:10:46 +0300349 rp->num_controllers = cpu_to_le16(count);
350 rp_len = sizeof(*rp) + (2 * count);
351
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200352 read_unlock(&hci_dev_list_lock);
353
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200354 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300355 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 kfree(rp);
358
359 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360}
361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200363{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 settings |= MGMT_SETTING_PAIRABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800368 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg03811012010-12-08 00:21:06 +0200369
Andre Guedesed3fa312012-07-24 15:03:46 -0300370 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300371 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500372 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
373 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300374 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 settings |= MGMT_SETTING_BREDR;
376 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700377
378 if (lmp_ssp_capable(hdev)) {
379 settings |= MGMT_SETTING_SSP;
380 settings |= MGMT_SETTING_HS;
381 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800382
Marcel Holtmann5afeac142014-01-10 02:07:27 -0800383 if (lmp_sc_capable(hdev) ||
384 test_bit(HCI_FORCE_SC, &hdev->dev_flags))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800385 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700386 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100387
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300388 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200389 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300390 settings |= MGMT_SETTING_ADVERTISING;
391 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200392
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200393 return settings;
394}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200395
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200396static u32 get_current_settings(struct hci_dev *hdev)
397{
398 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200399
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200400 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100401 settings |= MGMT_SETTING_POWERED;
402
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200403 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200404 settings |= MGMT_SETTING_CONNECTABLE;
405
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500406 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
407 settings |= MGMT_SETTING_FAST_CONNECTABLE;
408
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200409 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200410 settings |= MGMT_SETTING_DISCOVERABLE;
411
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200412 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200413 settings |= MGMT_SETTING_PAIRABLE;
414
Johan Hedberg56f87902013-10-02 13:43:13 +0300415 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200416 settings |= MGMT_SETTING_BREDR;
417
Johan Hedberg06199cf2012-02-22 16:37:11 +0200418 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200419 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200420
Johan Hedberg47990ea2012-02-22 11:58:37 +0200421 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200423
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200424 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200425 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200426
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200427 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
428 settings |= MGMT_SETTING_HS;
429
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200430 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300431 settings |= MGMT_SETTING_ADVERTISING;
432
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800433 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
434 settings |= MGMT_SETTING_SECURE_CONN;
435
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800436 if (test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags))
437 settings |= MGMT_SETTING_DEBUG_KEYS;
438
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200439 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200440}
441
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300442#define PNP_INFO_SVCLASS_ID 0x1200
443
Johan Hedberg213202e2013-01-27 00:31:33 +0200444static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
445{
446 u8 *ptr = data, *uuids_start = NULL;
447 struct bt_uuid *uuid;
448
449 if (len < 4)
450 return ptr;
451
452 list_for_each_entry(uuid, &hdev->uuids, list) {
453 u16 uuid16;
454
455 if (uuid->size != 16)
456 continue;
457
458 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
459 if (uuid16 < 0x1100)
460 continue;
461
462 if (uuid16 == PNP_INFO_SVCLASS_ID)
463 continue;
464
465 if (!uuids_start) {
466 uuids_start = ptr;
467 uuids_start[0] = 1;
468 uuids_start[1] = EIR_UUID16_ALL;
469 ptr += 2;
470 }
471
472 /* Stop if not enough space to put next UUID */
473 if ((ptr - data) + sizeof(u16) > len) {
474 uuids_start[1] = EIR_UUID16_SOME;
475 break;
476 }
477
478 *ptr++ = (uuid16 & 0x00ff);
479 *ptr++ = (uuid16 & 0xff00) >> 8;
480 uuids_start[0] += sizeof(uuid16);
481 }
482
483 return ptr;
484}
485
Johan Hedbergcdf19632013-01-27 00:31:34 +0200486static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
487{
488 u8 *ptr = data, *uuids_start = NULL;
489 struct bt_uuid *uuid;
490
491 if (len < 6)
492 return ptr;
493
494 list_for_each_entry(uuid, &hdev->uuids, list) {
495 if (uuid->size != 32)
496 continue;
497
498 if (!uuids_start) {
499 uuids_start = ptr;
500 uuids_start[0] = 1;
501 uuids_start[1] = EIR_UUID32_ALL;
502 ptr += 2;
503 }
504
505 /* Stop if not enough space to put next UUID */
506 if ((ptr - data) + sizeof(u32) > len) {
507 uuids_start[1] = EIR_UUID32_SOME;
508 break;
509 }
510
511 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
512 ptr += sizeof(u32);
513 uuids_start[0] += sizeof(u32);
514 }
515
516 return ptr;
517}
518
Johan Hedbergc00d5752013-01-27 00:31:35 +0200519static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
520{
521 u8 *ptr = data, *uuids_start = NULL;
522 struct bt_uuid *uuid;
523
524 if (len < 18)
525 return ptr;
526
527 list_for_each_entry(uuid, &hdev->uuids, list) {
528 if (uuid->size != 128)
529 continue;
530
531 if (!uuids_start) {
532 uuids_start = ptr;
533 uuids_start[0] = 1;
534 uuids_start[1] = EIR_UUID128_ALL;
535 ptr += 2;
536 }
537
538 /* Stop if not enough space to put next UUID */
539 if ((ptr - data) + 16 > len) {
540 uuids_start[1] = EIR_UUID128_SOME;
541 break;
542 }
543
544 memcpy(ptr, uuid->uuid, 16);
545 ptr += 16;
546 uuids_start[0] += 16;
547 }
548
549 return ptr;
550}
551
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300552static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
553{
554 struct pending_cmd *cmd;
555
556 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
557 if (cmd->opcode == opcode)
558 return cmd;
559 }
560
561 return NULL;
562}
563
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700564static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
565{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700566 u8 ad_len = 0;
567 size_t name_len;
568
569 name_len = strlen(hdev->dev_name);
570 if (name_len > 0) {
571 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
572
573 if (name_len > max_len) {
574 name_len = max_len;
575 ptr[1] = EIR_NAME_SHORT;
576 } else
577 ptr[1] = EIR_NAME_COMPLETE;
578
579 ptr[0] = name_len + 1;
580
581 memcpy(ptr + 2, hdev->dev_name, name_len);
582
583 ad_len += (name_len + 2);
584 ptr += (name_len + 2);
585 }
586
587 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700588}
589
590static void update_scan_rsp_data(struct hci_request *req)
591{
592 struct hci_dev *hdev = req->hdev;
593 struct hci_cp_le_set_scan_rsp_data cp;
594 u8 len;
595
Johan Hedberg7751ef12013-10-19 23:38:15 +0300596 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700597 return;
598
599 memset(&cp, 0, sizeof(cp));
600
601 len = create_scan_rsp_data(hdev, cp.data);
602
Johan Hedbergeb438b52013-10-16 15:31:07 +0300603 if (hdev->scan_rsp_data_len == len &&
604 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700605 return;
606
Johan Hedbergeb438b52013-10-16 15:31:07 +0300607 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
608 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700609
610 cp.length = len;
611
612 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
613}
614
Johan Hedberg9a43e252013-10-20 19:00:07 +0300615static u8 get_adv_discov_flags(struct hci_dev *hdev)
616{
617 struct pending_cmd *cmd;
618
619 /* If there's a pending mgmt command the flags will not yet have
620 * their final values, so check for this first.
621 */
622 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
623 if (cmd) {
624 struct mgmt_mode *cp = cmd->param;
625 if (cp->val == 0x01)
626 return LE_AD_GENERAL;
627 else if (cp->val == 0x02)
628 return LE_AD_LIMITED;
629 } else {
630 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
631 return LE_AD_LIMITED;
632 else if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
633 return LE_AD_GENERAL;
634 }
635
636 return 0;
637}
638
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700639static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700640{
641 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700642
Johan Hedberg9a43e252013-10-20 19:00:07 +0300643 flags |= get_adv_discov_flags(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700644
Johan Hedberge8340042014-01-30 11:16:50 -0800645 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700646 flags |= LE_AD_NO_BREDR;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700647
648 if (flags) {
649 BT_DBG("adv flags 0x%02x", flags);
650
651 ptr[0] = 2;
652 ptr[1] = EIR_FLAGS;
653 ptr[2] = flags;
654
655 ad_len += 3;
656 ptr += 3;
657 }
658
659 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
660 ptr[0] = 2;
661 ptr[1] = EIR_TX_POWER;
662 ptr[2] = (u8) hdev->adv_tx_power;
663
664 ad_len += 3;
665 ptr += 3;
666 }
667
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700668 return ad_len;
669}
670
Marcel Holtmann5947f4b2013-10-16 00:16:50 -0700671static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700672{
673 struct hci_dev *hdev = req->hdev;
674 struct hci_cp_le_set_adv_data cp;
675 u8 len;
676
Johan Hedberg10994ce2013-10-19 23:38:16 +0300677 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700678 return;
679
680 memset(&cp, 0, sizeof(cp));
681
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700682 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700683
684 if (hdev->adv_data_len == len &&
685 memcmp(cp.data, hdev->adv_data, len) == 0)
686 return;
687
688 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
689 hdev->adv_data_len = len;
690
691 cp.length = len;
692
693 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
694}
695
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300696static void create_eir(struct hci_dev *hdev, u8 *data)
697{
698 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300699 size_t name_len;
700
701 name_len = strlen(hdev->dev_name);
702
703 if (name_len > 0) {
704 /* EIR Data type */
705 if (name_len > 48) {
706 name_len = 48;
707 ptr[1] = EIR_NAME_SHORT;
708 } else
709 ptr[1] = EIR_NAME_COMPLETE;
710
711 /* EIR Data length */
712 ptr[0] = name_len + 1;
713
714 memcpy(ptr + 2, hdev->dev_name, name_len);
715
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300716 ptr += (name_len + 2);
717 }
718
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100719 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700720 ptr[0] = 2;
721 ptr[1] = EIR_TX_POWER;
722 ptr[2] = (u8) hdev->inq_tx_power;
723
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700724 ptr += 3;
725 }
726
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700727 if (hdev->devid_source > 0) {
728 ptr[0] = 9;
729 ptr[1] = EIR_DEVICE_ID;
730
731 put_unaligned_le16(hdev->devid_source, ptr + 2);
732 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
733 put_unaligned_le16(hdev->devid_product, ptr + 6);
734 put_unaligned_le16(hdev->devid_version, ptr + 8);
735
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700736 ptr += 10;
737 }
738
Johan Hedberg213202e2013-01-27 00:31:33 +0200739 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200740 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200741 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300742}
743
Johan Hedberg890ea892013-03-15 17:06:52 -0500744static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300745{
Johan Hedberg890ea892013-03-15 17:06:52 -0500746 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300747 struct hci_cp_write_eir cp;
748
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200749 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500750 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200751
Johan Hedberg976eb202012-10-24 21:12:01 +0300752 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500753 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300754
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200755 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500756 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300757
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200758 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500759 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300760
761 memset(&cp, 0, sizeof(cp));
762
763 create_eir(hdev, cp.data);
764
765 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500766 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300767
768 memcpy(hdev->eir, cp.data, sizeof(cp.data));
769
Johan Hedberg890ea892013-03-15 17:06:52 -0500770 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300771}
772
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200773static u8 get_service_classes(struct hci_dev *hdev)
774{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300775 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200776 u8 val = 0;
777
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300778 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200779 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200780
781 return val;
782}
783
Johan Hedberg890ea892013-03-15 17:06:52 -0500784static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200785{
Johan Hedberg890ea892013-03-15 17:06:52 -0500786 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200787 u8 cod[3];
788
789 BT_DBG("%s", hdev->name);
790
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200791 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500792 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200793
Johan Hedbergf87ea1d2013-10-19 23:38:17 +0300794 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
795 return;
796
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200797 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500798 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200799
800 cod[0] = hdev->minor_class;
801 cod[1] = hdev->major_class;
802 cod[2] = get_service_classes(hdev);
803
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700804 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
805 cod[1] |= 0x20;
806
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200807 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500808 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200809
Johan Hedberg890ea892013-03-15 17:06:52 -0500810 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200811}
812
Johan Hedberg7d785252011-12-15 00:47:39 +0200813static void service_cache_off(struct work_struct *work)
814{
815 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300816 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500817 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200818
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200819 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200820 return;
821
Johan Hedberg890ea892013-03-15 17:06:52 -0500822 hci_req_init(&req, hdev);
823
Johan Hedberg7d785252011-12-15 00:47:39 +0200824 hci_dev_lock(hdev);
825
Johan Hedberg890ea892013-03-15 17:06:52 -0500826 update_eir(&req);
827 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200828
829 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500830
831 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200832}
833
Johan Hedberg6a919082012-02-28 06:17:26 +0200834static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200835{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200836 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200837 return;
838
Johan Hedberg4f87da82012-03-02 19:55:56 +0200839 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200840
Johan Hedberg4f87da82012-03-02 19:55:56 +0200841 /* Non-mgmt controlled devices get this bit set
842 * implicitly so that pairing works for them, however
843 * for mgmt we require user-space to explicitly enable
844 * it
845 */
846 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200847}
848
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200849static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300850 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200851{
852 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200853
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200854 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200855
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300856 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200857
Johan Hedberg03811012010-12-08 00:21:06 +0200858 memset(&rp, 0, sizeof(rp));
859
Johan Hedberg03811012010-12-08 00:21:06 +0200860 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200861
862 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200863 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200864
865 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
866 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
867
868 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200869
870 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200871 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200872
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300873 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200874
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200875 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300876 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200877}
878
879static void mgmt_pending_free(struct pending_cmd *cmd)
880{
881 sock_put(cmd->sk);
882 kfree(cmd->param);
883 kfree(cmd);
884}
885
886static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300887 struct hci_dev *hdev, void *data,
888 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200889{
890 struct pending_cmd *cmd;
891
Andre Guedes12b94562012-06-07 19:05:45 -0300892 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200893 if (!cmd)
894 return NULL;
895
896 cmd->opcode = opcode;
897 cmd->index = hdev->id;
898
Andre Guedes12b94562012-06-07 19:05:45 -0300899 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200900 if (!cmd->param) {
901 kfree(cmd);
902 return NULL;
903 }
904
905 if (data)
906 memcpy(cmd->param, data, len);
907
908 cmd->sk = sk;
909 sock_hold(sk);
910
911 list_add(&cmd->list, &hdev->mgmt_pending);
912
913 return cmd;
914}
915
916static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300917 void (*cb)(struct pending_cmd *cmd,
918 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300919 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200920{
Andre Guedesa3d09352013-02-01 11:21:30 -0300921 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200922
Andre Guedesa3d09352013-02-01 11:21:30 -0300923 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200924 if (opcode > 0 && cmd->opcode != opcode)
925 continue;
926
927 cb(cmd, data);
928 }
929}
930
Johan Hedberg03811012010-12-08 00:21:06 +0200931static void mgmt_pending_remove(struct pending_cmd *cmd)
932{
933 list_del(&cmd->list);
934 mgmt_pending_free(cmd);
935}
936
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200937static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200938{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200939 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200940
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200941 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300942 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200943}
944
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200945static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300946 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200947{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300948 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200949 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200950 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200951
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200952 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200953
Johan Hedberga7e80f22013-01-09 16:05:19 +0200954 if (cp->val != 0x00 && cp->val != 0x01)
955 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
956 MGMT_STATUS_INVALID_PARAMS);
957
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300958 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200959
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300960 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
961 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
962 MGMT_STATUS_BUSY);
963 goto failed;
964 }
965
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100966 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
967 cancel_delayed_work(&hdev->power_off);
968
969 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200970 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
971 data, len);
972 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100973 goto failed;
974 }
975 }
976
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200977 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200978 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200979 goto failed;
980 }
981
Johan Hedberg03811012010-12-08 00:21:06 +0200982 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
983 if (!cmd) {
984 err = -ENOMEM;
985 goto failed;
986 }
987
988 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200989 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200990 else
Johan Hedberg19202572013-01-14 22:33:51 +0200991 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200992
993 err = 0;
994
995failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300996 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200997 return err;
998}
999
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001000static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
1001 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001002{
1003 struct sk_buff *skb;
1004 struct mgmt_hdr *hdr;
1005
Andre Guedes790eff42012-06-07 19:05:46 -03001006 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001007 if (!skb)
1008 return -ENOMEM;
1009
1010 hdr = (void *) skb_put(skb, sizeof(*hdr));
1011 hdr->opcode = cpu_to_le16(event);
1012 if (hdev)
1013 hdr->index = cpu_to_le16(hdev->id);
1014 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05301015 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001016 hdr->len = cpu_to_le16(data_len);
1017
1018 if (data)
1019 memcpy(skb_put(skb, data_len), data, data_len);
1020
Marcel Holtmann97e0bde2012-02-22 13:49:28 +01001021 /* Time stamp */
1022 __net_timestamp(skb);
1023
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001024 hci_send_to_control(skb, skip_sk);
1025 kfree_skb(skb);
1026
1027 return 0;
1028}
1029
1030static int new_settings(struct hci_dev *hdev, struct sock *skip)
1031{
1032 __le32 ev;
1033
1034 ev = cpu_to_le32(get_current_settings(hdev));
1035
1036 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1037}
1038
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001039struct cmd_lookup {
1040 struct sock *sk;
1041 struct hci_dev *hdev;
1042 u8 mgmt_status;
1043};
1044
1045static void settings_rsp(struct pending_cmd *cmd, void *data)
1046{
1047 struct cmd_lookup *match = data;
1048
1049 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1050
1051 list_del(&cmd->list);
1052
1053 if (match->sk == NULL) {
1054 match->sk = cmd->sk;
1055 sock_hold(match->sk);
1056 }
1057
1058 mgmt_pending_free(cmd);
1059}
1060
1061static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1062{
1063 u8 *status = data;
1064
1065 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1066 mgmt_pending_remove(cmd);
1067}
1068
Johan Hedberge6fe7982013-10-02 15:45:22 +03001069static u8 mgmt_bredr_support(struct hci_dev *hdev)
1070{
1071 if (!lmp_bredr_capable(hdev))
1072 return MGMT_STATUS_NOT_SUPPORTED;
1073 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1074 return MGMT_STATUS_REJECTED;
1075 else
1076 return MGMT_STATUS_SUCCESS;
1077}
1078
1079static u8 mgmt_le_support(struct hci_dev *hdev)
1080{
1081 if (!lmp_le_capable(hdev))
1082 return MGMT_STATUS_NOT_SUPPORTED;
1083 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1084 return MGMT_STATUS_REJECTED;
1085 else
1086 return MGMT_STATUS_SUCCESS;
1087}
1088
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001089static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1090{
1091 struct pending_cmd *cmd;
1092 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001093 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001094 bool changed;
1095
1096 BT_DBG("status 0x%02x", status);
1097
1098 hci_dev_lock(hdev);
1099
1100 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1101 if (!cmd)
1102 goto unlock;
1103
1104 if (status) {
1105 u8 mgmt_err = mgmt_status(status);
1106 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001107 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001108 goto remove_cmd;
1109 }
1110
1111 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001112 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001113 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1114 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001115
1116 if (hdev->discov_timeout > 0) {
1117 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1118 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1119 to);
1120 }
1121 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001122 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1123 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001124 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001125
1126 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1127
1128 if (changed)
1129 new_settings(hdev, cmd->sk);
1130
Marcel Holtmann970ba522013-10-15 06:33:57 -07001131 /* When the discoverable mode gets changed, make sure
1132 * that class of device has the limited discoverable
1133 * bit correctly set.
1134 */
1135 hci_req_init(&req, hdev);
1136 update_class(&req);
1137 hci_req_run(&req, NULL);
1138
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001139remove_cmd:
1140 mgmt_pending_remove(cmd);
1141
1142unlock:
1143 hci_dev_unlock(hdev);
1144}
1145
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001146static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001147 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001148{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001149 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001150 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001151 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001152 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001153 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001154 int err;
1155
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001156 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001157
Johan Hedberg9a43e252013-10-20 19:00:07 +03001158 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1159 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001160 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberg9a43e252013-10-20 19:00:07 +03001161 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001162
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001163 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga7e80f22013-01-09 16:05:19 +02001164 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1165 MGMT_STATUS_INVALID_PARAMS);
1166
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001167 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001168
1169 /* Disabling discoverable requires that no timeout is set,
1170 * and enabling limited discoverable requires a timeout.
1171 */
1172 if ((cp->val == 0x00 && timeout > 0) ||
1173 (cp->val == 0x02 && timeout == 0))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001174 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001175 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001176
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001177 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001178
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001179 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001180 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001181 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001182 goto failed;
1183 }
1184
1185 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001186 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001187 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001188 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001189 goto failed;
1190 }
1191
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001192 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001193 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001194 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001195 goto failed;
1196 }
1197
1198 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001199 bool changed = false;
1200
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001201 /* Setting limited discoverable when powered off is
1202 * not a valid operation since it requires a timeout
1203 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1204 */
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001205 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1206 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1207 changed = true;
1208 }
1209
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001210 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001211 if (err < 0)
1212 goto failed;
1213
1214 if (changed)
1215 err = new_settings(hdev, sk);
1216
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001217 goto failed;
1218 }
1219
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001220 /* If the current mode is the same, then just update the timeout
1221 * value with the new value. And if only the timeout gets updated,
1222 * then no need for any HCI transactions.
1223 */
1224 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) &&
1225 (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE,
1226 &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001227 cancel_delayed_work(&hdev->discov_off);
1228 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001229
Marcel Holtmann36261542013-10-15 08:28:51 -07001230 if (cp->val && hdev->discov_timeout > 0) {
1231 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001232 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001233 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001234 }
1235
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001236 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001237 goto failed;
1238 }
1239
1240 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1241 if (!cmd) {
1242 err = -ENOMEM;
1243 goto failed;
1244 }
1245
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001246 /* Cancel any potential discoverable timeout that might be
1247 * still active and store new timeout value. The arming of
1248 * the timeout happens in the complete handler.
1249 */
1250 cancel_delayed_work(&hdev->discov_off);
1251 hdev->discov_timeout = timeout;
1252
Johan Hedbergb456f872013-10-19 23:38:22 +03001253 /* Limited discoverable mode */
1254 if (cp->val == 0x02)
1255 set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1256 else
1257 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1258
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001259 hci_req_init(&req, hdev);
1260
Johan Hedberg9a43e252013-10-20 19:00:07 +03001261 /* The procedure for LE-only controllers is much simpler - just
1262 * update the advertising data.
1263 */
1264 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1265 goto update_ad;
1266
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001267 scan = SCAN_PAGE;
1268
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001269 if (cp->val) {
1270 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001271
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001272 if (cp->val == 0x02) {
1273 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001274 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001275 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1276 hci_cp.iac_lap[1] = 0x8b;
1277 hci_cp.iac_lap[2] = 0x9e;
1278 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1279 hci_cp.iac_lap[4] = 0x8b;
1280 hci_cp.iac_lap[5] = 0x9e;
1281 } else {
1282 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001283 hci_cp.num_iac = 1;
1284 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1285 hci_cp.iac_lap[1] = 0x8b;
1286 hci_cp.iac_lap[2] = 0x9e;
1287 }
1288
1289 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1290 (hci_cp.num_iac * 3) + 1, &hci_cp);
1291
1292 scan |= SCAN_INQUIRY;
1293 } else {
1294 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1295 }
1296
1297 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001298
Johan Hedberg9a43e252013-10-20 19:00:07 +03001299update_ad:
1300 update_adv_data(&req);
1301
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001302 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001303 if (err < 0)
1304 mgmt_pending_remove(cmd);
1305
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001306failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001307 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001308 return err;
1309}
1310
Johan Hedberg406d7802013-03-15 17:07:09 -05001311static void write_fast_connectable(struct hci_request *req, bool enable)
1312{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001313 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001314 struct hci_cp_write_page_scan_activity acp;
1315 u8 type;
1316
Johan Hedberg547003b2013-10-21 16:51:53 +03001317 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1318 return;
1319
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001320 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1321 return;
1322
Johan Hedberg406d7802013-03-15 17:07:09 -05001323 if (enable) {
1324 type = PAGE_SCAN_TYPE_INTERLACED;
1325
1326 /* 160 msec page scan interval */
1327 acp.interval = __constant_cpu_to_le16(0x0100);
1328 } else {
1329 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1330
1331 /* default 1.28 sec page scan */
1332 acp.interval = __constant_cpu_to_le16(0x0800);
1333 }
1334
1335 acp.window = __constant_cpu_to_le16(0x0012);
1336
Johan Hedbergbd98b992013-03-15 17:07:13 -05001337 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1338 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1339 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1340 sizeof(acp), &acp);
1341
1342 if (hdev->page_scan_type != type)
1343 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001344}
1345
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001346static u8 get_adv_type(struct hci_dev *hdev)
1347{
1348 struct pending_cmd *cmd;
1349 bool connectable;
1350
1351 /* If there's a pending mgmt command the flag will not yet have
1352 * it's final value, so check for this first.
1353 */
1354 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1355 if (cmd) {
1356 struct mgmt_mode *cp = cmd->param;
1357 connectable = !!cp->val;
1358 } else {
1359 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1360 }
1361
1362 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1363}
1364
Johan Hedberg95c66e72013-10-14 16:20:06 +03001365static void enable_advertising(struct hci_request *req)
1366{
1367 struct hci_dev *hdev = req->hdev;
1368 struct hci_cp_le_set_adv_param cp;
1369 u8 enable = 0x01;
1370
1371 memset(&cp, 0, sizeof(cp));
1372 cp.min_interval = __constant_cpu_to_le16(0x0800);
1373 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001374 cp.type = get_adv_type(hdev);
Marcel Holtmann79830f62013-10-18 16:38:09 -07001375 cp.own_address_type = hdev->own_addr_type;
Johan Hedberg95c66e72013-10-14 16:20:06 +03001376 cp.channel_map = 0x07;
1377
1378 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1379
1380 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1381}
1382
1383static void disable_advertising(struct hci_request *req)
1384{
1385 u8 enable = 0x00;
1386
1387 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1388}
1389
Johan Hedberg2b76f452013-03-15 17:07:04 -05001390static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1391{
1392 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001393 struct mgmt_mode *cp;
1394 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001395
1396 BT_DBG("status 0x%02x", status);
1397
1398 hci_dev_lock(hdev);
1399
1400 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1401 if (!cmd)
1402 goto unlock;
1403
Johan Hedberg37438c12013-10-14 16:20:05 +03001404 if (status) {
1405 u8 mgmt_err = mgmt_status(status);
1406 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1407 goto remove_cmd;
1408 }
1409
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001410 cp = cmd->param;
1411 if (cp->val)
1412 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1413 else
1414 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1415
Johan Hedberg2b76f452013-03-15 17:07:04 -05001416 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1417
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001418 if (changed)
1419 new_settings(hdev, cmd->sk);
1420
Johan Hedberg37438c12013-10-14 16:20:05 +03001421remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001422 mgmt_pending_remove(cmd);
1423
1424unlock:
1425 hci_dev_unlock(hdev);
1426}
1427
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001428static int set_connectable_update_settings(struct hci_dev *hdev,
1429 struct sock *sk, u8 val)
1430{
1431 bool changed = false;
1432 int err;
1433
1434 if (!!val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1435 changed = true;
1436
1437 if (val) {
1438 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1439 } else {
1440 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1441 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1442 }
1443
1444 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1445 if (err < 0)
1446 return err;
1447
1448 if (changed)
1449 return new_settings(hdev, sk);
1450
1451 return 0;
1452}
1453
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001454static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001455 u16 len)
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001456{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001457 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001458 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001459 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001460 u8 scan;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001461 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001462
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001463 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001464
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001465 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1466 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001467 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001468 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001469
Johan Hedberga7e80f22013-01-09 16:05:19 +02001470 if (cp->val != 0x00 && cp->val != 0x01)
1471 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1472 MGMT_STATUS_INVALID_PARAMS);
1473
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001474 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001475
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001476 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001477 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001478 goto failed;
1479 }
1480
1481 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001482 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001483 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001484 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001485 goto failed;
1486 }
1487
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001488 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1489 if (!cmd) {
1490 err = -ENOMEM;
1491 goto failed;
1492 }
1493
Johan Hedberg2b76f452013-03-15 17:07:04 -05001494 hci_req_init(&req, hdev);
1495
Johan Hedberg9a43e252013-10-20 19:00:07 +03001496 /* If BR/EDR is not enabled and we disable advertising as a
1497 * by-product of disabling connectable, we need to update the
1498 * advertising flags.
1499 */
1500 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
1501 if (!cp->val) {
1502 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1503 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1504 }
1505 update_adv_data(&req);
1506 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001507 if (cp->val) {
1508 scan = SCAN_PAGE;
1509 } else {
1510 scan = 0;
1511
1512 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001513 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001514 cancel_delayed_work(&hdev->discov_off);
1515 }
1516
1517 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1518 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001519
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001520 /* If we're going from non-connectable to connectable or
1521 * vice-versa when fast connectable is enabled ensure that fast
1522 * connectable gets disabled. write_fast_connectable won't do
1523 * anything if the page scan parameters are already what they
1524 * should be.
1525 */
1526 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001527 write_fast_connectable(&req, false);
1528
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001529 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1530 hci_conn_num(hdev, LE_LINK) == 0) {
1531 disable_advertising(&req);
1532 enable_advertising(&req);
1533 }
1534
Johan Hedberg2b76f452013-03-15 17:07:04 -05001535 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001536 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001537 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001538 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03001539 err = set_connectable_update_settings(hdev, sk,
1540 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03001541 goto failed;
1542 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001543
1544failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001545 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001546 return err;
1547}
1548
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001549static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001550 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001551{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001552 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001553 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001554 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001555
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001556 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001557
Johan Hedberga7e80f22013-01-09 16:05:19 +02001558 if (cp->val != 0x00 && cp->val != 0x01)
1559 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1560 MGMT_STATUS_INVALID_PARAMS);
1561
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001562 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001563
1564 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001565 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001566 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001567 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001568
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001569 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001570 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001571 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001572
Marcel Holtmann55594352013-10-06 16:11:57 -07001573 if (changed)
1574 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001575
Marcel Holtmann55594352013-10-06 16:11:57 -07001576unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001577 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001578 return err;
1579}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001580
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001581static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1582 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001583{
1584 struct mgmt_mode *cp = data;
1585 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001586 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001587 int err;
1588
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001589 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001590
Johan Hedberge6fe7982013-10-02 15:45:22 +03001591 status = mgmt_bredr_support(hdev);
1592 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001593 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001594 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001595
Johan Hedberga7e80f22013-01-09 16:05:19 +02001596 if (cp->val != 0x00 && cp->val != 0x01)
1597 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1598 MGMT_STATUS_INVALID_PARAMS);
1599
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001600 hci_dev_lock(hdev);
1601
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001602 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001603 bool changed = false;
1604
1605 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001606 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001607 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1608 changed = true;
1609 }
1610
1611 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1612 if (err < 0)
1613 goto failed;
1614
1615 if (changed)
1616 err = new_settings(hdev, sk);
1617
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001618 goto failed;
1619 }
1620
1621 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001622 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001623 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001624 goto failed;
1625 }
1626
1627 val = !!cp->val;
1628
1629 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1630 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1631 goto failed;
1632 }
1633
1634 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1635 if (!cmd) {
1636 err = -ENOMEM;
1637 goto failed;
1638 }
1639
1640 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1641 if (err < 0) {
1642 mgmt_pending_remove(cmd);
1643 goto failed;
1644 }
1645
1646failed:
1647 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001648 return err;
1649}
1650
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001651static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001652{
1653 struct mgmt_mode *cp = data;
1654 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001655 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001656 int err;
1657
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001658 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001659
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001660 status = mgmt_bredr_support(hdev);
1661 if (status)
1662 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1663
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001664 if (!lmp_ssp_capable(hdev))
1665 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1666 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001667
Johan Hedberga7e80f22013-01-09 16:05:19 +02001668 if (cp->val != 0x00 && cp->val != 0x01)
1669 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1670 MGMT_STATUS_INVALID_PARAMS);
1671
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001672 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001673
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001674 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001675 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001676
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001677 if (cp->val) {
1678 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1679 &hdev->dev_flags);
1680 } else {
1681 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1682 &hdev->dev_flags);
1683 if (!changed)
1684 changed = test_and_clear_bit(HCI_HS_ENABLED,
1685 &hdev->dev_flags);
1686 else
1687 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001688 }
1689
1690 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1691 if (err < 0)
1692 goto failed;
1693
1694 if (changed)
1695 err = new_settings(hdev, sk);
1696
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001697 goto failed;
1698 }
1699
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001700 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1701 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001702 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1703 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001704 goto failed;
1705 }
1706
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001707 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001708 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1709 goto failed;
1710 }
1711
1712 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1713 if (!cmd) {
1714 err = -ENOMEM;
1715 goto failed;
1716 }
1717
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001718 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001719 if (err < 0) {
1720 mgmt_pending_remove(cmd);
1721 goto failed;
1722 }
1723
1724failed:
1725 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001726 return err;
1727}
1728
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001729static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001730{
1731 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001732 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001733 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001734 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001735
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001736 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001737
Johan Hedberge6fe7982013-10-02 15:45:22 +03001738 status = mgmt_bredr_support(hdev);
1739 if (status)
1740 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001741
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001742 if (!lmp_ssp_capable(hdev))
1743 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1744 MGMT_STATUS_NOT_SUPPORTED);
1745
1746 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1747 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1748 MGMT_STATUS_REJECTED);
1749
Johan Hedberga7e80f22013-01-09 16:05:19 +02001750 if (cp->val != 0x00 && cp->val != 0x01)
1751 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1752 MGMT_STATUS_INVALID_PARAMS);
1753
Marcel Holtmannee392692013-10-01 22:59:23 -07001754 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001755
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001756 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001757 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001758 } else {
1759 if (hdev_is_powered(hdev)) {
1760 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1761 MGMT_STATUS_REJECTED);
1762 goto unlock;
1763 }
1764
Marcel Holtmannee392692013-10-01 22:59:23 -07001765 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001766 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001767
1768 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1769 if (err < 0)
1770 goto unlock;
1771
1772 if (changed)
1773 err = new_settings(hdev, sk);
1774
1775unlock:
1776 hci_dev_unlock(hdev);
1777 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001778}
1779
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001780static void le_enable_complete(struct hci_dev *hdev, u8 status)
1781{
1782 struct cmd_lookup match = { NULL, hdev };
1783
1784 if (status) {
1785 u8 mgmt_err = mgmt_status(status);
1786
1787 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1788 &mgmt_err);
1789 return;
1790 }
1791
1792 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1793
1794 new_settings(hdev, match.sk);
1795
1796 if (match.sk)
1797 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001798
1799 /* Make sure the controller has a good default for
1800 * advertising data. Restrict the update to when LE
1801 * has actually been enabled. During power on, the
1802 * update in powered_update_hci will take care of it.
1803 */
1804 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1805 struct hci_request req;
1806
1807 hci_dev_lock(hdev);
1808
1809 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001810 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07001811 update_scan_rsp_data(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001812 hci_req_run(&req, NULL);
1813
1814 hci_dev_unlock(hdev);
1815 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001816}
1817
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001818static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001819{
1820 struct mgmt_mode *cp = data;
1821 struct hci_cp_write_le_host_supported hci_cp;
1822 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001823 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001824 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001825 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001826
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001827 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001828
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001829 if (!lmp_le_capable(hdev))
1830 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1831 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001832
Johan Hedberga7e80f22013-01-09 16:05:19 +02001833 if (cp->val != 0x00 && cp->val != 0x01)
1834 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1835 MGMT_STATUS_INVALID_PARAMS);
1836
Johan Hedbergc73eee92013-04-19 18:35:21 +03001837 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001838 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001839 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1840 MGMT_STATUS_REJECTED);
1841
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001842 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001843
1844 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001845 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001846
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001847 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001848 bool changed = false;
1849
1850 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1851 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1852 changed = true;
1853 }
1854
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001855 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1856 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001857 changed = true;
1858 }
1859
Johan Hedberg06199cf2012-02-22 16:37:11 +02001860 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1861 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001862 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001863
1864 if (changed)
1865 err = new_settings(hdev, sk);
1866
Johan Hedberg1de028c2012-02-29 19:55:35 -08001867 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001868 }
1869
Johan Hedberg4375f102013-09-25 13:26:10 +03001870 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1871 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001872 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001873 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001874 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001875 }
1876
1877 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1878 if (!cmd) {
1879 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001880 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001881 }
1882
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001883 hci_req_init(&req, hdev);
1884
Johan Hedberg06199cf2012-02-22 16:37:11 +02001885 memset(&hci_cp, 0, sizeof(hci_cp));
1886
1887 if (val) {
1888 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001889 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001890 } else {
1891 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1892 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001893 }
1894
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001895 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1896 &hci_cp);
1897
1898 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301899 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001900 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001901
Johan Hedberg1de028c2012-02-29 19:55:35 -08001902unlock:
1903 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001904 return err;
1905}
1906
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001907/* This is a helper function to test for pending mgmt commands that can
1908 * cause CoD or EIR HCI commands. We can only allow one such pending
1909 * mgmt command at a time since otherwise we cannot easily track what
1910 * the current values are, will be, and based on that calculate if a new
1911 * HCI command needs to be sent and if yes with what value.
1912 */
1913static bool pending_eir_or_class(struct hci_dev *hdev)
1914{
1915 struct pending_cmd *cmd;
1916
1917 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1918 switch (cmd->opcode) {
1919 case MGMT_OP_ADD_UUID:
1920 case MGMT_OP_REMOVE_UUID:
1921 case MGMT_OP_SET_DEV_CLASS:
1922 case MGMT_OP_SET_POWERED:
1923 return true;
1924 }
1925 }
1926
1927 return false;
1928}
1929
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001930static const u8 bluetooth_base_uuid[] = {
1931 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1932 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1933};
1934
1935static u8 get_uuid_size(const u8 *uuid)
1936{
1937 u32 val;
1938
1939 if (memcmp(uuid, bluetooth_base_uuid, 12))
1940 return 128;
1941
1942 val = get_unaligned_le32(&uuid[12]);
1943 if (val > 0xffff)
1944 return 32;
1945
1946 return 16;
1947}
1948
Johan Hedberg92da6092013-03-15 17:06:55 -05001949static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1950{
1951 struct pending_cmd *cmd;
1952
1953 hci_dev_lock(hdev);
1954
1955 cmd = mgmt_pending_find(mgmt_op, hdev);
1956 if (!cmd)
1957 goto unlock;
1958
1959 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1960 hdev->dev_class, 3);
1961
1962 mgmt_pending_remove(cmd);
1963
1964unlock:
1965 hci_dev_unlock(hdev);
1966}
1967
1968static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1969{
1970 BT_DBG("status 0x%02x", status);
1971
1972 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1973}
1974
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001975static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001976{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001977 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001978 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001979 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001980 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001981 int err;
1982
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001983 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001984
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001985 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001986
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001987 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001988 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001989 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001990 goto failed;
1991 }
1992
Andre Guedes92c4c202012-06-07 19:05:44 -03001993 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001994 if (!uuid) {
1995 err = -ENOMEM;
1996 goto failed;
1997 }
1998
1999 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002000 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002001 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002002
Johan Hedbergde66aa62013-01-27 00:31:27 +02002003 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002004
Johan Hedberg890ea892013-03-15 17:06:52 -05002005 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002006
Johan Hedberg890ea892013-03-15 17:06:52 -05002007 update_class(&req);
2008 update_eir(&req);
2009
Johan Hedberg92da6092013-03-15 17:06:55 -05002010 err = hci_req_run(&req, add_uuid_complete);
2011 if (err < 0) {
2012 if (err != -ENODATA)
2013 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002014
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002015 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002016 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002017 goto failed;
2018 }
2019
2020 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002021 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002022 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002023 goto failed;
2024 }
2025
2026 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002027
2028failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002029 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002030 return err;
2031}
2032
Johan Hedberg24b78d02012-02-23 23:24:30 +02002033static bool enable_service_cache(struct hci_dev *hdev)
2034{
2035 if (!hdev_is_powered(hdev))
2036 return false;
2037
2038 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002039 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2040 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002041 return true;
2042 }
2043
2044 return false;
2045}
2046
Johan Hedberg92da6092013-03-15 17:06:55 -05002047static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
2048{
2049 BT_DBG("status 0x%02x", status);
2050
2051 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2052}
2053
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002054static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002055 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002056{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002057 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002058 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002059 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002060 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg890ea892013-03-15 17:06:52 -05002061 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002062 int err, found;
2063
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002064 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002065
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002066 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002067
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002068 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002069 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002070 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002071 goto unlock;
2072 }
2073
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002074 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
2075 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002076
Johan Hedberg24b78d02012-02-23 23:24:30 +02002077 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002078 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002079 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002080 goto unlock;
2081 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002082
Johan Hedberg9246a862012-02-23 21:33:16 +02002083 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002084 }
2085
2086 found = 0;
2087
Johan Hedberg056341c2013-01-27 00:31:30 +02002088 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002089 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2090 continue;
2091
2092 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002093 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002094 found++;
2095 }
2096
2097 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002098 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002099 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002100 goto unlock;
2101 }
2102
Johan Hedberg9246a862012-02-23 21:33:16 +02002103update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002104 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002105
Johan Hedberg890ea892013-03-15 17:06:52 -05002106 update_class(&req);
2107 update_eir(&req);
2108
Johan Hedberg92da6092013-03-15 17:06:55 -05002109 err = hci_req_run(&req, remove_uuid_complete);
2110 if (err < 0) {
2111 if (err != -ENODATA)
2112 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002113
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002114 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002115 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002116 goto unlock;
2117 }
2118
2119 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002120 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002121 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002122 goto unlock;
2123 }
2124
2125 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002126
2127unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002128 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002129 return err;
2130}
2131
Johan Hedberg92da6092013-03-15 17:06:55 -05002132static void set_class_complete(struct hci_dev *hdev, u8 status)
2133{
2134 BT_DBG("status 0x%02x", status);
2135
2136 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2137}
2138
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002139static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002140 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002141{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002142 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002143 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002144 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002145 int err;
2146
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002147 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002148
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002149 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002150 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2151 MGMT_STATUS_NOT_SUPPORTED);
2152
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002153 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002154
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002155 if (pending_eir_or_class(hdev)) {
2156 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2157 MGMT_STATUS_BUSY);
2158 goto unlock;
2159 }
2160
2161 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2162 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2163 MGMT_STATUS_INVALID_PARAMS);
2164 goto unlock;
2165 }
2166
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002167 hdev->major_class = cp->major;
2168 hdev->minor_class = cp->minor;
2169
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002170 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002171 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002172 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002173 goto unlock;
2174 }
2175
Johan Hedberg890ea892013-03-15 17:06:52 -05002176 hci_req_init(&req, hdev);
2177
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002178 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002179 hci_dev_unlock(hdev);
2180 cancel_delayed_work_sync(&hdev->service_cache);
2181 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002182 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002183 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002184
Johan Hedberg890ea892013-03-15 17:06:52 -05002185 update_class(&req);
2186
Johan Hedberg92da6092013-03-15 17:06:55 -05002187 err = hci_req_run(&req, set_class_complete);
2188 if (err < 0) {
2189 if (err != -ENODATA)
2190 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002191
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002192 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002193 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002194 goto unlock;
2195 }
2196
2197 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002198 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002199 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002200 goto unlock;
2201 }
2202
2203 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002204
Johan Hedbergb5235a62012-02-21 14:32:24 +02002205unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002206 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002207 return err;
2208}
2209
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002210static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002211 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002212{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002213 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002214 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002215 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002216 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002217
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002218 BT_DBG("request for %s", hdev->name);
2219
2220 if (!lmp_bredr_capable(hdev))
2221 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2222 MGMT_STATUS_NOT_SUPPORTED);
2223
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002224 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002225
Johan Hedberg86742e12011-11-07 23:13:38 +02002226 expected_len = sizeof(*cp) + key_count *
2227 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002228 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002229 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002230 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002231 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002232 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002233 }
2234
Johan Hedberg4ae14302013-01-20 14:27:13 +02002235 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2236 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2237 MGMT_STATUS_INVALID_PARAMS);
2238
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002239 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002240 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002241
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002242 for (i = 0; i < key_count; i++) {
2243 struct mgmt_link_key_info *key = &cp->keys[i];
2244
Marcel Holtmann8e991132014-01-10 02:07:25 -08002245 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002246 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2247 MGMT_STATUS_INVALID_PARAMS);
2248 }
2249
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002250 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002251
2252 hci_link_keys_clear(hdev);
2253
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002254 if (cp->debug_keys)
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002255 changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002256 else
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002257 changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
2258
2259 if (changed)
2260 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002261
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002262 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002263 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002264
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002265 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002266 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002267 }
2268
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002269 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002270
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002271 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002272
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002273 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002274}
2275
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002276static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002277 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002278{
2279 struct mgmt_ev_device_unpaired ev;
2280
2281 bacpy(&ev.addr.bdaddr, bdaddr);
2282 ev.addr.type = addr_type;
2283
2284 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002285 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002286}
2287
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002288static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002289 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002290{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002291 struct mgmt_cp_unpair_device *cp = data;
2292 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002293 struct hci_cp_disconnect dc;
2294 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002295 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002296 int err;
2297
Johan Hedberga8a1d192011-11-10 15:54:38 +02002298 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002299 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2300 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002301
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002302 if (!bdaddr_type_is_valid(cp->addr.type))
2303 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2304 MGMT_STATUS_INVALID_PARAMS,
2305 &rp, sizeof(rp));
2306
Johan Hedberg118da702013-01-20 14:27:20 +02002307 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2308 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2309 MGMT_STATUS_INVALID_PARAMS,
2310 &rp, sizeof(rp));
2311
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002312 hci_dev_lock(hdev);
2313
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002314 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002315 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002316 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002317 goto unlock;
2318 }
2319
Andre Guedes591f47f2012-04-24 21:02:49 -03002320 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02002321 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
2322 else
2323 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002324
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002325 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002326 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002327 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002328 goto unlock;
2329 }
2330
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002331 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002332 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002333 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002334 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002335 else
2336 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002337 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002338 } else {
2339 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002340 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002341
Johan Hedberga8a1d192011-11-10 15:54:38 +02002342 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002343 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002344 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002345 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002346 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002347 }
2348
Johan Hedberg124f6e32012-02-09 13:50:12 +02002349 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002350 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002351 if (!cmd) {
2352 err = -ENOMEM;
2353 goto unlock;
2354 }
2355
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002356 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002357 dc.reason = 0x13; /* Remote User Terminated Connection */
2358 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2359 if (err < 0)
2360 mgmt_pending_remove(cmd);
2361
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002362unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002363 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002364 return err;
2365}
2366
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002367static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002368 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002369{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002370 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002371 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002372 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002373 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002374 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002375 int err;
2376
2377 BT_DBG("");
2378
Johan Hedberg06a63b12013-01-20 14:27:21 +02002379 memset(&rp, 0, sizeof(rp));
2380 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2381 rp.addr.type = cp->addr.type;
2382
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002383 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002384 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2385 MGMT_STATUS_INVALID_PARAMS,
2386 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002387
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002388 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002389
2390 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002391 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2392 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002393 goto failed;
2394 }
2395
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002396 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002397 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2398 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002399 goto failed;
2400 }
2401
Andre Guedes591f47f2012-04-24 21:02:49 -03002402 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002403 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2404 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002405 else
2406 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002407
Vishal Agarwalf9607272012-06-13 05:32:43 +05302408 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002409 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2410 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002411 goto failed;
2412 }
2413
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002414 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002415 if (!cmd) {
2416 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002417 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002418 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002419
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002420 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002421 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002422
2423 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2424 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002425 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002426
2427failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002428 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002429 return err;
2430}
2431
Andre Guedes57c14772012-04-24 21:02:50 -03002432static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002433{
2434 switch (link_type) {
2435 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002436 switch (addr_type) {
2437 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002438 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002439
Johan Hedberg48264f02011-11-09 13:58:58 +02002440 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002441 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002442 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002443 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002444
Johan Hedberg4c659c32011-11-07 23:13:39 +02002445 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002446 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002447 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002448 }
2449}
2450
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002451static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2452 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002453{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002454 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002455 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002456 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002457 int err;
2458 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002459
2460 BT_DBG("");
2461
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002462 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002463
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002464 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002465 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002466 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002467 goto unlock;
2468 }
2469
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002470 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002471 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2472 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002473 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002474 }
2475
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002476 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002477 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002478 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002479 err = -ENOMEM;
2480 goto unlock;
2481 }
2482
Johan Hedberg2784eb42011-01-21 13:56:35 +02002483 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002484 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002485 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2486 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002487 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002488 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002489 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002490 continue;
2491 i++;
2492 }
2493
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002494 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002495
Johan Hedberg4c659c32011-11-07 23:13:39 +02002496 /* Recalculate length in case of filtered SCO connections, etc */
2497 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002498
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002499 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002500 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002501
Johan Hedberga38528f2011-01-22 06:46:43 +02002502 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002503
2504unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002505 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002506 return err;
2507}
2508
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002509static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002510 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002511{
2512 struct pending_cmd *cmd;
2513 int err;
2514
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002515 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002516 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002517 if (!cmd)
2518 return -ENOMEM;
2519
Johan Hedbergd8457692012-02-17 14:24:57 +02002520 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002521 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002522 if (err < 0)
2523 mgmt_pending_remove(cmd);
2524
2525 return err;
2526}
2527
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002528static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002529 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002530{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002531 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002532 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002533 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002534 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002535 int err;
2536
2537 BT_DBG("");
2538
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002539 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002540
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002541 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002542 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002543 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002544 goto failed;
2545 }
2546
Johan Hedbergd8457692012-02-17 14:24:57 +02002547 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002548 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002549 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002550 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002551 goto failed;
2552 }
2553
2554 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002555 struct mgmt_cp_pin_code_neg_reply ncp;
2556
2557 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002558
2559 BT_ERR("PIN code is not 16 bytes long");
2560
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002561 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002562 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002563 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002564 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002565
2566 goto failed;
2567 }
2568
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002569 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002570 if (!cmd) {
2571 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002572 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002573 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002574
Johan Hedbergd8457692012-02-17 14:24:57 +02002575 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002576 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002577 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002578
2579 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2580 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002581 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002582
2583failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002584 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002585 return err;
2586}
2587
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002588static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2589 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002590{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002591 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002592
2593 BT_DBG("");
2594
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002595 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002596
2597 hdev->io_capability = cp->io_capability;
2598
2599 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002600 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002601
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002602 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002603
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002604 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2605 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002606}
2607
Gustavo Padovan6039aa732012-05-23 04:04:18 -03002608static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002609{
2610 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002611 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002612
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002613 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002614 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2615 continue;
2616
Johan Hedberge9a416b2011-02-19 12:05:56 -03002617 if (cmd->user_data != conn)
2618 continue;
2619
2620 return cmd;
2621 }
2622
2623 return NULL;
2624}
2625
2626static void pairing_complete(struct pending_cmd *cmd, u8 status)
2627{
2628 struct mgmt_rp_pair_device rp;
2629 struct hci_conn *conn = cmd->user_data;
2630
Johan Hedbergba4e5642011-11-11 00:07:34 +02002631 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002632 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002633
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002634 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002635 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002636
2637 /* So we don't get further callbacks for this connection */
2638 conn->connect_cfm_cb = NULL;
2639 conn->security_cfm_cb = NULL;
2640 conn->disconn_cfm_cb = NULL;
2641
David Herrmann76a68ba2013-04-06 20:28:37 +02002642 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002643
Johan Hedberga664b5b2011-02-19 12:06:02 -03002644 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002645}
2646
2647static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2648{
2649 struct pending_cmd *cmd;
2650
2651 BT_DBG("status %u", status);
2652
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002653 cmd = find_pairing(conn);
2654 if (!cmd)
2655 BT_DBG("Unable to find a pending command");
2656 else
Johan Hedberge2113262012-02-18 15:20:03 +02002657 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002658}
2659
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302660static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2661{
2662 struct pending_cmd *cmd;
2663
2664 BT_DBG("status %u", status);
2665
2666 if (!status)
2667 return;
2668
2669 cmd = find_pairing(conn);
2670 if (!cmd)
2671 BT_DBG("Unable to find a pending command");
2672 else
2673 pairing_complete(cmd, mgmt_status(status));
2674}
2675
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002676static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002677 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002678{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002679 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002680 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002681 struct pending_cmd *cmd;
2682 u8 sec_level, auth_type;
2683 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002684 int err;
2685
2686 BT_DBG("");
2687
Szymon Jancf950a30e2013-01-18 12:48:07 +01002688 memset(&rp, 0, sizeof(rp));
2689 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2690 rp.addr.type = cp->addr.type;
2691
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002692 if (!bdaddr_type_is_valid(cp->addr.type))
2693 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2694 MGMT_STATUS_INVALID_PARAMS,
2695 &rp, sizeof(rp));
2696
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002697 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002698
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002699 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002700 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2701 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002702 goto unlock;
2703 }
2704
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002705 sec_level = BT_SECURITY_MEDIUM;
2706 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002707 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002708 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002709 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002710
Andre Guedes591f47f2012-04-24 21:02:49 -03002711 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002712 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2713 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002714 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002715 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2716 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002717
Ville Tervo30e76272011-02-22 16:10:53 -03002718 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002719 int status;
2720
2721 if (PTR_ERR(conn) == -EBUSY)
2722 status = MGMT_STATUS_BUSY;
2723 else
2724 status = MGMT_STATUS_CONNECT_FAILED;
2725
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002726 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002727 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002728 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002729 goto unlock;
2730 }
2731
2732 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002733 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002734 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002735 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002736 goto unlock;
2737 }
2738
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002739 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002740 if (!cmd) {
2741 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002742 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002743 goto unlock;
2744 }
2745
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002746 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002747 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002748 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302749 else
2750 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002751
Johan Hedberge9a416b2011-02-19 12:05:56 -03002752 conn->security_cfm_cb = pairing_complete_cb;
2753 conn->disconn_cfm_cb = pairing_complete_cb;
2754 conn->io_capability = cp->io_cap;
2755 cmd->user_data = conn;
2756
2757 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002758 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002759 pairing_complete(cmd, 0);
2760
2761 err = 0;
2762
2763unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002764 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002765 return err;
2766}
2767
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002768static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2769 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002770{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002771 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002772 struct pending_cmd *cmd;
2773 struct hci_conn *conn;
2774 int err;
2775
2776 BT_DBG("");
2777
Johan Hedberg28424702012-02-02 04:02:29 +02002778 hci_dev_lock(hdev);
2779
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002780 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002781 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002782 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002783 goto unlock;
2784 }
2785
Johan Hedberg28424702012-02-02 04:02:29 +02002786 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2787 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002788 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002789 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002790 goto unlock;
2791 }
2792
2793 conn = cmd->user_data;
2794
2795 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002796 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002797 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002798 goto unlock;
2799 }
2800
2801 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2802
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002803 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002804 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002805unlock:
2806 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002807 return err;
2808}
2809
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002810static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002811 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002812 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002813{
Johan Hedberga5c29682011-02-19 12:05:57 -03002814 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002815 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002816 int err;
2817
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002818 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002819
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002820 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002821 err = cmd_complete(sk, hdev->id, mgmt_op,
2822 MGMT_STATUS_NOT_POWERED, addr,
2823 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002824 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002825 }
2826
Johan Hedberg1707c602013-03-15 17:07:15 -05002827 if (addr->type == BDADDR_BREDR)
2828 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002829 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002830 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002831
Johan Hedberg272d90d2012-02-09 15:26:12 +02002832 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002833 err = cmd_complete(sk, hdev->id, mgmt_op,
2834 MGMT_STATUS_NOT_CONNECTED, addr,
2835 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002836 goto done;
2837 }
2838
Johan Hedberg1707c602013-03-15 17:07:15 -05002839 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002840 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002841 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002842
Brian Gix5fe57d92011-12-21 16:12:13 -08002843 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002844 err = cmd_complete(sk, hdev->id, mgmt_op,
2845 MGMT_STATUS_SUCCESS, addr,
2846 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002847 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002848 err = cmd_complete(sk, hdev->id, mgmt_op,
2849 MGMT_STATUS_FAILED, addr,
2850 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002851
Brian Gix47c15e22011-11-16 13:53:14 -08002852 goto done;
2853 }
2854
Johan Hedberg1707c602013-03-15 17:07:15 -05002855 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002856 if (!cmd) {
2857 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002858 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002859 }
2860
Brian Gix0df4c182011-11-16 13:53:13 -08002861 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002862 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2863 struct hci_cp_user_passkey_reply cp;
2864
Johan Hedberg1707c602013-03-15 17:07:15 -05002865 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002866 cp.passkey = passkey;
2867 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2868 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002869 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2870 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002871
Johan Hedberga664b5b2011-02-19 12:06:02 -03002872 if (err < 0)
2873 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002874
Brian Gix0df4c182011-11-16 13:53:13 -08002875done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002876 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002877 return err;
2878}
2879
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302880static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2881 void *data, u16 len)
2882{
2883 struct mgmt_cp_pin_code_neg_reply *cp = data;
2884
2885 BT_DBG("");
2886
Johan Hedberg1707c602013-03-15 17:07:15 -05002887 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302888 MGMT_OP_PIN_CODE_NEG_REPLY,
2889 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2890}
2891
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002892static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2893 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002894{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002895 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002896
2897 BT_DBG("");
2898
2899 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002900 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002901 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002902
Johan Hedberg1707c602013-03-15 17:07:15 -05002903 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002904 MGMT_OP_USER_CONFIRM_REPLY,
2905 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002906}
2907
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002908static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002909 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002910{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002911 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002912
2913 BT_DBG("");
2914
Johan Hedberg1707c602013-03-15 17:07:15 -05002915 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002916 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2917 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002918}
2919
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002920static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2921 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002922{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002923 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002924
2925 BT_DBG("");
2926
Johan Hedberg1707c602013-03-15 17:07:15 -05002927 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002928 MGMT_OP_USER_PASSKEY_REPLY,
2929 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002930}
2931
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002932static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002933 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002934{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002935 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002936
2937 BT_DBG("");
2938
Johan Hedberg1707c602013-03-15 17:07:15 -05002939 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002940 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2941 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002942}
2943
Johan Hedberg13928972013-03-15 17:07:00 -05002944static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002945{
Johan Hedberg13928972013-03-15 17:07:00 -05002946 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002947 struct hci_cp_write_local_name cp;
2948
Johan Hedberg13928972013-03-15 17:07:00 -05002949 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002950
Johan Hedberg890ea892013-03-15 17:06:52 -05002951 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002952}
2953
Johan Hedberg13928972013-03-15 17:07:00 -05002954static void set_name_complete(struct hci_dev *hdev, u8 status)
2955{
2956 struct mgmt_cp_set_local_name *cp;
2957 struct pending_cmd *cmd;
2958
2959 BT_DBG("status 0x%02x", status);
2960
2961 hci_dev_lock(hdev);
2962
2963 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2964 if (!cmd)
2965 goto unlock;
2966
2967 cp = cmd->param;
2968
2969 if (status)
2970 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2971 mgmt_status(status));
2972 else
2973 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2974 cp, sizeof(*cp));
2975
2976 mgmt_pending_remove(cmd);
2977
2978unlock:
2979 hci_dev_unlock(hdev);
2980}
2981
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002982static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002983 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002984{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002985 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002986 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002987 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002988 int err;
2989
2990 BT_DBG("");
2991
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002992 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002993
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002994 /* If the old values are the same as the new ones just return a
2995 * direct command complete event.
2996 */
2997 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2998 !memcmp(hdev->short_name, cp->short_name,
2999 sizeof(hdev->short_name))) {
3000 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3001 data, len);
3002 goto failed;
3003 }
3004
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003005 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003006
Johan Hedbergb5235a62012-02-21 14:32:24 +02003007 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003008 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003009
3010 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003011 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003012 if (err < 0)
3013 goto failed;
3014
3015 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003016 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003017
Johan Hedbergb5235a62012-02-21 14:32:24 +02003018 goto failed;
3019 }
3020
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003021 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003022 if (!cmd) {
3023 err = -ENOMEM;
3024 goto failed;
3025 }
3026
Johan Hedberg13928972013-03-15 17:07:00 -05003027 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3028
Johan Hedberg890ea892013-03-15 17:06:52 -05003029 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003030
3031 if (lmp_bredr_capable(hdev)) {
3032 update_name(&req);
3033 update_eir(&req);
3034 }
3035
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003036 /* The name is stored in the scan response data and so
3037 * no need to udpate the advertising data here.
3038 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003039 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003040 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003041
Johan Hedberg13928972013-03-15 17:07:00 -05003042 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003043 if (err < 0)
3044 mgmt_pending_remove(cmd);
3045
3046failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003047 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003048 return err;
3049}
3050
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003051static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003052 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003053{
Szymon Jancc35938b2011-03-22 13:12:21 +01003054 struct pending_cmd *cmd;
3055 int err;
3056
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003057 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003058
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003059 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003060
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003061 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003062 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003063 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003064 goto unlock;
3065 }
3066
Andre Guedes9a1a1992012-07-24 15:03:48 -03003067 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003068 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003069 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003070 goto unlock;
3071 }
3072
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003073 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003074 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003075 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003076 goto unlock;
3077 }
3078
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003079 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003080 if (!cmd) {
3081 err = -ENOMEM;
3082 goto unlock;
3083 }
3084
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003085 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
3086 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
3087 0, NULL);
3088 else
3089 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3090
Szymon Jancc35938b2011-03-22 13:12:21 +01003091 if (err < 0)
3092 mgmt_pending_remove(cmd);
3093
3094unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003095 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003096 return err;
3097}
3098
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003099static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003100 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003101{
Szymon Janc2763eda2011-03-22 13:12:22 +01003102 int err;
3103
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003104 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003105
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003106 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003107
Marcel Holtmannec109112014-01-10 02:07:30 -08003108 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3109 struct mgmt_cp_add_remote_oob_data *cp = data;
3110 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003111
Marcel Holtmannec109112014-01-10 02:07:30 -08003112 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
3113 cp->hash, cp->randomizer);
3114 if (err < 0)
3115 status = MGMT_STATUS_FAILED;
3116 else
3117 status = MGMT_STATUS_SUCCESS;
3118
3119 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3120 status, &cp->addr, sizeof(cp->addr));
3121 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3122 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
3123 u8 status;
3124
3125 err = hci_add_remote_oob_ext_data(hdev, &cp->addr.bdaddr,
3126 cp->hash192,
3127 cp->randomizer192,
3128 cp->hash256,
3129 cp->randomizer256);
3130 if (err < 0)
3131 status = MGMT_STATUS_FAILED;
3132 else
3133 status = MGMT_STATUS_SUCCESS;
3134
3135 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3136 status, &cp->addr, sizeof(cp->addr));
3137 } else {
3138 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
3139 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3140 MGMT_STATUS_INVALID_PARAMS);
3141 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003142
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003143 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003144 return err;
3145}
3146
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003147static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003148 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003149{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003150 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003151 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003152 int err;
3153
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003154 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003155
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003156 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003157
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003158 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003159 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003160 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003161 else
Szymon Janca6785be2012-12-13 15:11:21 +01003162 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003163
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003164 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003165 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003166
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003167 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003168 return err;
3169}
3170
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003171static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3172{
3173 struct pending_cmd *cmd;
3174 u8 type;
3175 int err;
3176
3177 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3178
3179 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3180 if (!cmd)
3181 return -ENOENT;
3182
3183 type = hdev->discovery.type;
3184
3185 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3186 &type, sizeof(type));
3187 mgmt_pending_remove(cmd);
3188
3189 return err;
3190}
3191
Andre Guedes7c307722013-04-30 15:29:28 -03003192static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3193{
3194 BT_DBG("status %d", status);
3195
3196 if (status) {
3197 hci_dev_lock(hdev);
3198 mgmt_start_discovery_failed(hdev, status);
3199 hci_dev_unlock(hdev);
3200 return;
3201 }
3202
3203 hci_dev_lock(hdev);
3204 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3205 hci_dev_unlock(hdev);
3206
3207 switch (hdev->discovery.type) {
3208 case DISCOV_TYPE_LE:
3209 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003210 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003211 break;
3212
3213 case DISCOV_TYPE_INTERLEAVED:
3214 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003215 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003216 break;
3217
3218 case DISCOV_TYPE_BREDR:
3219 break;
3220
3221 default:
3222 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3223 }
3224}
3225
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003226static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003227 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003228{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003229 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003230 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003231 struct hci_cp_le_set_scan_param param_cp;
3232 struct hci_cp_le_set_scan_enable enable_cp;
3233 struct hci_cp_inquiry inq_cp;
3234 struct hci_request req;
3235 /* General inquiry access code (GIAC) */
3236 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003237 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003238 int err;
3239
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003240 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003241
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003242 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003243
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003244 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003245 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003246 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003247 goto failed;
3248 }
3249
Andre Guedes642be6c2012-03-21 00:03:37 -03003250 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3251 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3252 MGMT_STATUS_BUSY);
3253 goto failed;
3254 }
3255
Johan Hedbergff9ef572012-01-04 14:23:45 +02003256 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003257 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003258 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003259 goto failed;
3260 }
3261
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003262 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003263 if (!cmd) {
3264 err = -ENOMEM;
3265 goto failed;
3266 }
3267
Andre Guedes4aab14e2012-02-17 20:39:36 -03003268 hdev->discovery.type = cp->type;
3269
Andre Guedes7c307722013-04-30 15:29:28 -03003270 hci_req_init(&req, hdev);
3271
Andre Guedes4aab14e2012-02-17 20:39:36 -03003272 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003273 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003274 status = mgmt_bredr_support(hdev);
3275 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003276 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003277 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003278 mgmt_pending_remove(cmd);
3279 goto failed;
3280 }
3281
Andre Guedes7c307722013-04-30 15:29:28 -03003282 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3283 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3284 MGMT_STATUS_BUSY);
3285 mgmt_pending_remove(cmd);
3286 goto failed;
3287 }
3288
3289 hci_inquiry_cache_flush(hdev);
3290
3291 memset(&inq_cp, 0, sizeof(inq_cp));
3292 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003293 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003294 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003295 break;
3296
3297 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003298 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003299 status = mgmt_le_support(hdev);
3300 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003301 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003302 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003303 mgmt_pending_remove(cmd);
3304 goto failed;
3305 }
3306
Andre Guedes7c307722013-04-30 15:29:28 -03003307 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003308 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003309 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3310 MGMT_STATUS_NOT_SUPPORTED);
3311 mgmt_pending_remove(cmd);
3312 goto failed;
3313 }
3314
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003315 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003316 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3317 MGMT_STATUS_REJECTED);
3318 mgmt_pending_remove(cmd);
3319 goto failed;
3320 }
3321
3322 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3323 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3324 MGMT_STATUS_BUSY);
3325 mgmt_pending_remove(cmd);
3326 goto failed;
3327 }
3328
3329 memset(&param_cp, 0, sizeof(param_cp));
3330 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003331 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3332 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmann79830f62013-10-18 16:38:09 -07003333 param_cp.own_address_type = hdev->own_addr_type;
Andre Guedes7c307722013-04-30 15:29:28 -03003334 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3335 &param_cp);
3336
3337 memset(&enable_cp, 0, sizeof(enable_cp));
3338 enable_cp.enable = LE_SCAN_ENABLE;
3339 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3340 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3341 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003342 break;
3343
Andre Guedesf39799f2012-02-17 20:39:35 -03003344 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003345 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3346 MGMT_STATUS_INVALID_PARAMS);
3347 mgmt_pending_remove(cmd);
3348 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003349 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003350
Andre Guedes7c307722013-04-30 15:29:28 -03003351 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003352 if (err < 0)
3353 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003354 else
3355 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003356
3357failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003358 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003359 return err;
3360}
3361
Andre Guedes1183fdc2013-04-30 15:29:35 -03003362static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3363{
3364 struct pending_cmd *cmd;
3365 int err;
3366
3367 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3368 if (!cmd)
3369 return -ENOENT;
3370
3371 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3372 &hdev->discovery.type, sizeof(hdev->discovery.type));
3373 mgmt_pending_remove(cmd);
3374
3375 return err;
3376}
3377
Andre Guedes0e05bba2013-04-30 15:29:33 -03003378static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3379{
3380 BT_DBG("status %d", status);
3381
3382 hci_dev_lock(hdev);
3383
3384 if (status) {
3385 mgmt_stop_discovery_failed(hdev, status);
3386 goto unlock;
3387 }
3388
3389 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3390
3391unlock:
3392 hci_dev_unlock(hdev);
3393}
3394
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003395static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003396 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003397{
Johan Hedbergd9306502012-02-20 23:25:18 +02003398 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003399 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003400 struct hci_cp_remote_name_req_cancel cp;
3401 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003402 struct hci_request req;
3403 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003404 int err;
3405
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003406 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003407
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003408 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003409
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003410 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003411 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003412 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3413 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003414 goto unlock;
3415 }
3416
3417 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003418 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003419 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3420 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003421 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003422 }
3423
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003424 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003425 if (!cmd) {
3426 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003427 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003428 }
3429
Andre Guedes0e05bba2013-04-30 15:29:33 -03003430 hci_req_init(&req, hdev);
3431
Andre Guedese0d9727e2012-03-20 15:15:36 -03003432 switch (hdev->discovery.state) {
3433 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003434 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3435 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3436 } else {
3437 cancel_delayed_work(&hdev->le_scan_disable);
3438
3439 memset(&enable_cp, 0, sizeof(enable_cp));
3440 enable_cp.enable = LE_SCAN_DISABLE;
3441 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3442 sizeof(enable_cp), &enable_cp);
3443 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003444
Andre Guedese0d9727e2012-03-20 15:15:36 -03003445 break;
3446
3447 case DISCOVERY_RESOLVING:
3448 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003449 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003450 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003451 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003452 err = cmd_complete(sk, hdev->id,
3453 MGMT_OP_STOP_DISCOVERY, 0,
3454 &mgmt_cp->type,
3455 sizeof(mgmt_cp->type));
3456 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3457 goto unlock;
3458 }
3459
3460 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003461 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3462 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003463
3464 break;
3465
3466 default:
3467 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003468
3469 mgmt_pending_remove(cmd);
3470 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3471 MGMT_STATUS_FAILED, &mgmt_cp->type,
3472 sizeof(mgmt_cp->type));
3473 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003474 }
3475
Andre Guedes0e05bba2013-04-30 15:29:33 -03003476 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003477 if (err < 0)
3478 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003479 else
3480 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003481
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003482unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003483 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003484 return err;
3485}
3486
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003487static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003488 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003489{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003490 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003491 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003492 int err;
3493
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003494 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003495
Johan Hedberg561aafb2012-01-04 13:31:59 +02003496 hci_dev_lock(hdev);
3497
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003498 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003499 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003500 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003501 goto failed;
3502 }
3503
Johan Hedberga198e7b2012-02-17 14:27:06 +02003504 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003505 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003506 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003507 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003508 goto failed;
3509 }
3510
3511 if (cp->name_known) {
3512 e->name_state = NAME_KNOWN;
3513 list_del(&e->list);
3514 } else {
3515 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003516 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003517 }
3518
Johan Hedberge3846622013-01-09 15:29:33 +02003519 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3520 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003521
3522failed:
3523 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003524 return err;
3525}
3526
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003527static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003528 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003529{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003530 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003531 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003532 int err;
3533
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003534 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003535
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003536 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003537 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3538 MGMT_STATUS_INVALID_PARAMS,
3539 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003540
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003541 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003542
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003543 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003544 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003545 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003546 else
Szymon Janca6785be2012-12-13 15:11:21 +01003547 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003548
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003549 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003550 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003551
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003552 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003553
3554 return err;
3555}
3556
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003557static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003558 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003559{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003560 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003561 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003562 int err;
3563
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003564 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003565
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003566 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003567 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3568 MGMT_STATUS_INVALID_PARAMS,
3569 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003570
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003571 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003572
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003573 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003574 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003575 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003576 else
Szymon Janca6785be2012-12-13 15:11:21 +01003577 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003578
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003579 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003580 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003581
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003582 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003583
3584 return err;
3585}
3586
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003587static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3588 u16 len)
3589{
3590 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003591 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003592 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003593 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003594
3595 BT_DBG("%s", hdev->name);
3596
Szymon Jancc72d4b82012-03-16 16:02:57 +01003597 source = __le16_to_cpu(cp->source);
3598
3599 if (source > 0x0002)
3600 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3601 MGMT_STATUS_INVALID_PARAMS);
3602
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003603 hci_dev_lock(hdev);
3604
Szymon Jancc72d4b82012-03-16 16:02:57 +01003605 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003606 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3607 hdev->devid_product = __le16_to_cpu(cp->product);
3608 hdev->devid_version = __le16_to_cpu(cp->version);
3609
3610 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3611
Johan Hedberg890ea892013-03-15 17:06:52 -05003612 hci_req_init(&req, hdev);
3613 update_eir(&req);
3614 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003615
3616 hci_dev_unlock(hdev);
3617
3618 return err;
3619}
3620
Johan Hedberg4375f102013-09-25 13:26:10 +03003621static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3622{
3623 struct cmd_lookup match = { NULL, hdev };
3624
3625 if (status) {
3626 u8 mgmt_err = mgmt_status(status);
3627
3628 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3629 cmd_status_rsp, &mgmt_err);
3630 return;
3631 }
3632
3633 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3634 &match);
3635
3636 new_settings(hdev, match.sk);
3637
3638 if (match.sk)
3639 sock_put(match.sk);
3640}
3641
Marcel Holtmann21b51872013-10-10 09:47:53 -07003642static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3643 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003644{
3645 struct mgmt_mode *cp = data;
3646 struct pending_cmd *cmd;
3647 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003648 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003649 int err;
3650
3651 BT_DBG("request for %s", hdev->name);
3652
Johan Hedberge6fe7982013-10-02 15:45:22 +03003653 status = mgmt_le_support(hdev);
3654 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003655 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003656 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003657
3658 if (cp->val != 0x00 && cp->val != 0x01)
3659 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3660 MGMT_STATUS_INVALID_PARAMS);
3661
3662 hci_dev_lock(hdev);
3663
3664 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003665 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003666
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003667 /* The following conditions are ones which mean that we should
3668 * not do any HCI communication but directly send a mgmt
3669 * response to user space (after toggling the flag if
3670 * necessary).
3671 */
3672 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003673 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003674 bool changed = false;
3675
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003676 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3677 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003678 changed = true;
3679 }
3680
3681 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3682 if (err < 0)
3683 goto unlock;
3684
3685 if (changed)
3686 err = new_settings(hdev, sk);
3687
3688 goto unlock;
3689 }
3690
3691 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3692 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3693 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3694 MGMT_STATUS_BUSY);
3695 goto unlock;
3696 }
3697
3698 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3699 if (!cmd) {
3700 err = -ENOMEM;
3701 goto unlock;
3702 }
3703
3704 hci_req_init(&req, hdev);
3705
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003706 if (val)
3707 enable_advertising(&req);
3708 else
3709 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003710
3711 err = hci_req_run(&req, set_advertising_complete);
3712 if (err < 0)
3713 mgmt_pending_remove(cmd);
3714
3715unlock:
3716 hci_dev_unlock(hdev);
3717 return err;
3718}
3719
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003720static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3721 void *data, u16 len)
3722{
3723 struct mgmt_cp_set_static_address *cp = data;
3724 int err;
3725
3726 BT_DBG("%s", hdev->name);
3727
Marcel Holtmann62af4442013-10-02 22:10:32 -07003728 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003729 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003730 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003731
3732 if (hdev_is_powered(hdev))
3733 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3734 MGMT_STATUS_REJECTED);
3735
3736 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3737 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3738 return cmd_status(sk, hdev->id,
3739 MGMT_OP_SET_STATIC_ADDRESS,
3740 MGMT_STATUS_INVALID_PARAMS);
3741
3742 /* Two most significant bits shall be set */
3743 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3744 return cmd_status(sk, hdev->id,
3745 MGMT_OP_SET_STATIC_ADDRESS,
3746 MGMT_STATUS_INVALID_PARAMS);
3747 }
3748
3749 hci_dev_lock(hdev);
3750
3751 bacpy(&hdev->static_addr, &cp->bdaddr);
3752
3753 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3754
3755 hci_dev_unlock(hdev);
3756
3757 return err;
3758}
3759
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003760static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3761 void *data, u16 len)
3762{
3763 struct mgmt_cp_set_scan_params *cp = data;
3764 __u16 interval, window;
3765 int err;
3766
3767 BT_DBG("%s", hdev->name);
3768
3769 if (!lmp_le_capable(hdev))
3770 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3771 MGMT_STATUS_NOT_SUPPORTED);
3772
3773 interval = __le16_to_cpu(cp->interval);
3774
3775 if (interval < 0x0004 || interval > 0x4000)
3776 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3777 MGMT_STATUS_INVALID_PARAMS);
3778
3779 window = __le16_to_cpu(cp->window);
3780
3781 if (window < 0x0004 || window > 0x4000)
3782 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3783 MGMT_STATUS_INVALID_PARAMS);
3784
Marcel Holtmann899e1072013-10-14 09:55:32 -07003785 if (window > interval)
3786 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3787 MGMT_STATUS_INVALID_PARAMS);
3788
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003789 hci_dev_lock(hdev);
3790
3791 hdev->le_scan_interval = interval;
3792 hdev->le_scan_window = window;
3793
3794 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3795
3796 hci_dev_unlock(hdev);
3797
3798 return err;
3799}
3800
Johan Hedberg33e38b32013-03-15 17:07:05 -05003801static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3802{
3803 struct pending_cmd *cmd;
3804
3805 BT_DBG("status 0x%02x", status);
3806
3807 hci_dev_lock(hdev);
3808
3809 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3810 if (!cmd)
3811 goto unlock;
3812
3813 if (status) {
3814 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3815 mgmt_status(status));
3816 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003817 struct mgmt_mode *cp = cmd->param;
3818
3819 if (cp->val)
3820 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3821 else
3822 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3823
Johan Hedberg33e38b32013-03-15 17:07:05 -05003824 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3825 new_settings(hdev, cmd->sk);
3826 }
3827
3828 mgmt_pending_remove(cmd);
3829
3830unlock:
3831 hci_dev_unlock(hdev);
3832}
3833
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003834static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003835 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003836{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003837 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003838 struct pending_cmd *cmd;
3839 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003840 int err;
3841
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003842 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003843
Johan Hedberg56f87902013-10-02 13:43:13 +03003844 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3845 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003846 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3847 MGMT_STATUS_NOT_SUPPORTED);
3848
Johan Hedberga7e80f22013-01-09 16:05:19 +02003849 if (cp->val != 0x00 && cp->val != 0x01)
3850 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3851 MGMT_STATUS_INVALID_PARAMS);
3852
Johan Hedberg5400c042012-02-21 16:40:33 +02003853 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003854 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003855 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003856
3857 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003858 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003859 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003860
3861 hci_dev_lock(hdev);
3862
Johan Hedberg05cbf292013-03-15 17:07:07 -05003863 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3864 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3865 MGMT_STATUS_BUSY);
3866 goto unlock;
3867 }
3868
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003869 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3870 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3871 hdev);
3872 goto unlock;
3873 }
3874
Johan Hedberg33e38b32013-03-15 17:07:05 -05003875 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3876 data, len);
3877 if (!cmd) {
3878 err = -ENOMEM;
3879 goto unlock;
3880 }
3881
3882 hci_req_init(&req, hdev);
3883
Johan Hedberg406d7802013-03-15 17:07:09 -05003884 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003885
3886 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003887 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003888 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003889 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003890 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003891 }
3892
Johan Hedberg33e38b32013-03-15 17:07:05 -05003893unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003894 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003895
Antti Julkuf6422ec2011-06-22 13:11:56 +03003896 return err;
3897}
3898
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003899static void set_bredr_scan(struct hci_request *req)
3900{
3901 struct hci_dev *hdev = req->hdev;
3902 u8 scan = 0;
3903
3904 /* Ensure that fast connectable is disabled. This function will
3905 * not do anything if the page scan parameters are already what
3906 * they should be.
3907 */
3908 write_fast_connectable(req, false);
3909
3910 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3911 scan |= SCAN_PAGE;
3912 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3913 scan |= SCAN_INQUIRY;
3914
3915 if (scan)
3916 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3917}
3918
Johan Hedberg0663ca22013-10-02 13:43:14 +03003919static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3920{
3921 struct pending_cmd *cmd;
3922
3923 BT_DBG("status 0x%02x", status);
3924
3925 hci_dev_lock(hdev);
3926
3927 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3928 if (!cmd)
3929 goto unlock;
3930
3931 if (status) {
3932 u8 mgmt_err = mgmt_status(status);
3933
3934 /* We need to restore the flag if related HCI commands
3935 * failed.
3936 */
3937 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3938
3939 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3940 } else {
3941 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3942 new_settings(hdev, cmd->sk);
3943 }
3944
3945 mgmt_pending_remove(cmd);
3946
3947unlock:
3948 hci_dev_unlock(hdev);
3949}
3950
3951static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3952{
3953 struct mgmt_mode *cp = data;
3954 struct pending_cmd *cmd;
3955 struct hci_request req;
3956 int err;
3957
3958 BT_DBG("request for %s", hdev->name);
3959
3960 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3961 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3962 MGMT_STATUS_NOT_SUPPORTED);
3963
3964 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3965 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3966 MGMT_STATUS_REJECTED);
3967
3968 if (cp->val != 0x00 && cp->val != 0x01)
3969 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3970 MGMT_STATUS_INVALID_PARAMS);
3971
3972 hci_dev_lock(hdev);
3973
3974 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3975 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3976 goto unlock;
3977 }
3978
3979 if (!hdev_is_powered(hdev)) {
3980 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003981 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3982 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3983 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3984 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3985 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3986 }
3987
3988 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3989
3990 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3991 if (err < 0)
3992 goto unlock;
3993
3994 err = new_settings(hdev, sk);
3995 goto unlock;
3996 }
3997
3998 /* Reject disabling when powered on */
3999 if (!cp->val) {
4000 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4001 MGMT_STATUS_REJECTED);
4002 goto unlock;
4003 }
4004
4005 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
4006 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4007 MGMT_STATUS_BUSY);
4008 goto unlock;
4009 }
4010
4011 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4012 if (!cmd) {
4013 err = -ENOMEM;
4014 goto unlock;
4015 }
4016
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004017 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03004018 * generates the correct flags.
4019 */
4020 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4021
4022 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004023
4024 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4025 set_bredr_scan(&req);
4026
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004027 /* Since only the advertising data flags will change, there
4028 * is no need to update the scan response data.
4029 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004030 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004031
Johan Hedberg0663ca22013-10-02 13:43:14 +03004032 err = hci_req_run(&req, set_bredr_complete);
4033 if (err < 0)
4034 mgmt_pending_remove(cmd);
4035
4036unlock:
4037 hci_dev_unlock(hdev);
4038 return err;
4039}
4040
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004041static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4042 void *data, u16 len)
4043{
4044 struct mgmt_mode *cp = data;
4045 struct pending_cmd *cmd;
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004046 u8 val, status;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004047 int err;
4048
4049 BT_DBG("request for %s", hdev->name);
4050
4051 status = mgmt_bredr_support(hdev);
4052 if (status)
4053 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4054 status);
4055
Marcel Holtmann5afeac142014-01-10 02:07:27 -08004056 if (!lmp_sc_capable(hdev) &&
4057 !test_bit(HCI_FORCE_SC, &hdev->dev_flags))
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004058 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4059 MGMT_STATUS_NOT_SUPPORTED);
4060
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004061 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004062 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4063 MGMT_STATUS_INVALID_PARAMS);
4064
4065 hci_dev_lock(hdev);
4066
4067 if (!hdev_is_powered(hdev)) {
4068 bool changed;
4069
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004070 if (cp->val) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004071 changed = !test_and_set_bit(HCI_SC_ENABLED,
4072 &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004073 if (cp->val == 0x02)
4074 set_bit(HCI_SC_ONLY, &hdev->dev_flags);
4075 else
4076 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4077 } else {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004078 changed = test_and_clear_bit(HCI_SC_ENABLED,
4079 &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004080 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4081 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004082
4083 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4084 if (err < 0)
4085 goto failed;
4086
4087 if (changed)
4088 err = new_settings(hdev, sk);
4089
4090 goto failed;
4091 }
4092
4093 if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
4094 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4095 MGMT_STATUS_BUSY);
4096 goto failed;
4097 }
4098
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004099 val = !!cp->val;
4100
4101 if (val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
4102 (cp->val == 0x02) == test_bit(HCI_SC_ONLY, &hdev->dev_flags)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004103 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4104 goto failed;
4105 }
4106
4107 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4108 if (!cmd) {
4109 err = -ENOMEM;
4110 goto failed;
4111 }
4112
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004113 err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004114 if (err < 0) {
4115 mgmt_pending_remove(cmd);
4116 goto failed;
4117 }
4118
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004119 if (cp->val == 0x02)
4120 set_bit(HCI_SC_ONLY, &hdev->dev_flags);
4121 else
4122 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4123
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004124failed:
4125 hci_dev_unlock(hdev);
4126 return err;
4127}
4128
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004129static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4130 void *data, u16 len)
4131{
4132 struct mgmt_mode *cp = data;
4133 bool changed;
4134 int err;
4135
4136 BT_DBG("request for %s", hdev->name);
4137
4138 if (cp->val != 0x00 && cp->val != 0x01)
4139 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4140 MGMT_STATUS_INVALID_PARAMS);
4141
4142 hci_dev_lock(hdev);
4143
4144 if (cp->val)
4145 changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
4146 else
4147 changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
4148
4149 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4150 if (err < 0)
4151 goto unlock;
4152
4153 if (changed)
4154 err = new_settings(hdev, sk);
4155
4156unlock:
4157 hci_dev_unlock(hdev);
4158 return err;
4159}
4160
Johan Hedberg3f706b72013-01-20 14:27:16 +02004161static bool ltk_is_valid(struct mgmt_ltk_info *key)
4162{
4163 if (key->master != 0x00 && key->master != 0x01)
4164 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004165
4166 switch (key->addr.type) {
4167 case BDADDR_LE_PUBLIC:
4168 return true;
4169
4170 case BDADDR_LE_RANDOM:
4171 /* Two most significant bits shall be set */
4172 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4173 return false;
4174 return true;
4175 }
4176
4177 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004178}
4179
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004180static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004181 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004182{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004183 struct mgmt_cp_load_long_term_keys *cp = cp_data;
4184 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004185 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004186
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004187 BT_DBG("request for %s", hdev->name);
4188
4189 if (!lmp_le_capable(hdev))
4190 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4191 MGMT_STATUS_NOT_SUPPORTED);
4192
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004193 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004194
4195 expected_len = sizeof(*cp) + key_count *
4196 sizeof(struct mgmt_ltk_info);
4197 if (expected_len != len) {
4198 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004199 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004200 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02004201 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004202 }
4203
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004204 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004205
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004206 for (i = 0; i < key_count; i++) {
4207 struct mgmt_ltk_info *key = &cp->keys[i];
4208
Johan Hedberg3f706b72013-01-20 14:27:16 +02004209 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004210 return cmd_status(sk, hdev->id,
4211 MGMT_OP_LOAD_LONG_TERM_KEYS,
4212 MGMT_STATUS_INVALID_PARAMS);
4213 }
4214
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004215 hci_dev_lock(hdev);
4216
4217 hci_smp_ltks_clear(hdev);
4218
4219 for (i = 0; i < key_count; i++) {
4220 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004221 u8 type, addr_type;
4222
4223 if (key->addr.type == BDADDR_LE_PUBLIC)
4224 addr_type = ADDR_LE_DEV_PUBLIC;
4225 else
4226 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004227
4228 if (key->master)
4229 type = HCI_SMP_LTK;
4230 else
4231 type = HCI_SMP_LTK_SLAVE;
4232
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004233 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Marcel Holtmannd40f3ee2014-01-31 18:42:17 -08004234 type, 0, key->type, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004235 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004236 }
4237
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004238 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4239 NULL, 0);
4240
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004241 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004242
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004243 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004244}
4245
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004246static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004247 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4248 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004249 bool var_len;
4250 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004251} mgmt_handlers[] = {
4252 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004253 { read_version, false, MGMT_READ_VERSION_SIZE },
4254 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4255 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4256 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4257 { set_powered, false, MGMT_SETTING_SIZE },
4258 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4259 { set_connectable, false, MGMT_SETTING_SIZE },
4260 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4261 { set_pairable, false, MGMT_SETTING_SIZE },
4262 { set_link_security, false, MGMT_SETTING_SIZE },
4263 { set_ssp, false, MGMT_SETTING_SIZE },
4264 { set_hs, false, MGMT_SETTING_SIZE },
4265 { set_le, false, MGMT_SETTING_SIZE },
4266 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4267 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4268 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4269 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4270 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4271 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4272 { disconnect, false, MGMT_DISCONNECT_SIZE },
4273 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4274 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4275 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4276 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4277 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4278 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4279 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4280 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4281 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4282 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4283 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4284 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
Marcel Holtmannec109112014-01-10 02:07:30 -08004285 { add_remote_oob_data, true, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
Johan Hedbergbe22b542012-03-01 22:24:41 +02004286 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4287 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4288 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4289 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4290 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4291 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004292 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004293 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004294 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004295 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004296 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004297 { set_secure_conn, false, MGMT_SETTING_SIZE },
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004298 { set_debug_keys, false, MGMT_SETTING_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004299};
4300
4301
Johan Hedberg03811012010-12-08 00:21:06 +02004302int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4303{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004304 void *buf;
4305 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004306 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004307 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004308 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004309 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004310 int err;
4311
4312 BT_DBG("got %zu bytes", msglen);
4313
4314 if (msglen < sizeof(*hdr))
4315 return -EINVAL;
4316
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004317 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004318 if (!buf)
4319 return -ENOMEM;
4320
4321 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4322 err = -EFAULT;
4323 goto done;
4324 }
4325
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004326 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004327 opcode = __le16_to_cpu(hdr->opcode);
4328 index = __le16_to_cpu(hdr->index);
4329 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004330
4331 if (len != msglen - sizeof(*hdr)) {
4332 err = -EINVAL;
4333 goto done;
4334 }
4335
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004336 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004337 hdev = hci_dev_get(index);
4338 if (!hdev) {
4339 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004340 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004341 goto done;
4342 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004343
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004344 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4345 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004346 err = cmd_status(sk, index, opcode,
4347 MGMT_STATUS_INVALID_INDEX);
4348 goto done;
4349 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004350 }
4351
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004352 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004353 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004354 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004355 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004356 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004357 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004358 }
4359
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004360 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004361 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004362 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004363 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004364 goto done;
4365 }
4366
Johan Hedbergbe22b542012-03-01 22:24:41 +02004367 handler = &mgmt_handlers[opcode];
4368
4369 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004370 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004371 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004372 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004373 goto done;
4374 }
4375
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004376 if (hdev)
4377 mgmt_init_hdev(sk, hdev);
4378
4379 cp = buf + sizeof(*hdr);
4380
Johan Hedbergbe22b542012-03-01 22:24:41 +02004381 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004382 if (err < 0)
4383 goto done;
4384
Johan Hedberg03811012010-12-08 00:21:06 +02004385 err = msglen;
4386
4387done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004388 if (hdev)
4389 hci_dev_put(hdev);
4390
Johan Hedberg03811012010-12-08 00:21:06 +02004391 kfree(buf);
4392 return err;
4393}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004394
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004395void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004396{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004397 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004398 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004399
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004400 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004401}
4402
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004403void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004404{
Johan Hedberg5f159032012-03-02 03:13:19 +02004405 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004406
Marcel Holtmann1514b892013-10-06 08:25:01 -07004407 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004408 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004409
Johan Hedberg744cf192011-11-08 20:40:14 +02004410 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004411
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004412 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004413}
4414
Johan Hedberg229ab392013-03-15 17:06:53 -05004415static void powered_complete(struct hci_dev *hdev, u8 status)
4416{
4417 struct cmd_lookup match = { NULL, hdev };
4418
4419 BT_DBG("status 0x%02x", status);
4420
4421 hci_dev_lock(hdev);
4422
4423 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4424
4425 new_settings(hdev, match.sk);
4426
4427 hci_dev_unlock(hdev);
4428
4429 if (match.sk)
4430 sock_put(match.sk);
4431}
4432
Johan Hedberg70da6242013-03-15 17:06:51 -05004433static int powered_update_hci(struct hci_dev *hdev)
4434{
Johan Hedberg890ea892013-03-15 17:06:52 -05004435 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004436 u8 link_sec;
4437
Johan Hedberg890ea892013-03-15 17:06:52 -05004438 hci_req_init(&req, hdev);
4439
Johan Hedberg70da6242013-03-15 17:06:51 -05004440 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4441 !lmp_host_ssp_capable(hdev)) {
4442 u8 ssp = 1;
4443
Johan Hedberg890ea892013-03-15 17:06:52 -05004444 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004445 }
4446
Johan Hedbergc73eee92013-04-19 18:35:21 +03004447 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4448 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004449 struct hci_cp_write_le_host_supported cp;
4450
4451 cp.le = 1;
4452 cp.simul = lmp_le_br_capable(hdev);
4453
4454 /* Check first if we already have the right
4455 * host state (host features set)
4456 */
4457 if (cp.le != lmp_host_le_capable(hdev) ||
4458 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004459 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4460 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004461 }
4462
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004463 if (lmp_le_capable(hdev)) {
4464 /* Set random address to static address if configured */
4465 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4466 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4467 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004468
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004469 /* Make sure the controller has a good default for
4470 * advertising data. This also applies to the case
4471 * where BR/EDR was toggled during the AUTO_OFF phase.
4472 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004473 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004474 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004475 update_scan_rsp_data(&req);
4476 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004477
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004478 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4479 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004480 }
4481
Johan Hedberg70da6242013-03-15 17:06:51 -05004482 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4483 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004484 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4485 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004486
4487 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004488 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4489 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004490 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004491 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004492 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004493 }
4494
Johan Hedberg229ab392013-03-15 17:06:53 -05004495 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004496}
4497
Johan Hedberg744cf192011-11-08 20:40:14 +02004498int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004499{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004500 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004501 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4502 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004503 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004504
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004505 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4506 return 0;
4507
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004508 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004509 if (powered_update_hci(hdev) == 0)
4510 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004511
Johan Hedberg229ab392013-03-15 17:06:53 -05004512 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4513 &match);
4514 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004515 }
4516
Johan Hedberg229ab392013-03-15 17:06:53 -05004517 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4518 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4519
4520 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4521 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4522 zero_cod, sizeof(zero_cod), NULL);
4523
4524new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004525 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004526
4527 if (match.sk)
4528 sock_put(match.sk);
4529
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004530 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004531}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004532
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004533void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004534{
4535 struct pending_cmd *cmd;
4536 u8 status;
4537
4538 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4539 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004540 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004541
4542 if (err == -ERFKILL)
4543 status = MGMT_STATUS_RFKILLED;
4544 else
4545 status = MGMT_STATUS_FAILED;
4546
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004547 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004548
4549 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004550}
4551
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004552void mgmt_discoverable_timeout(struct hci_dev *hdev)
4553{
4554 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004555
4556 hci_dev_lock(hdev);
4557
4558 /* When discoverable timeout triggers, then just make sure
4559 * the limited discoverable flag is cleared. Even in the case
4560 * of a timeout triggered from general discoverable, it is
4561 * safe to unconditionally clear the flag.
4562 */
4563 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004564 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004565
4566 hci_req_init(&req, hdev);
Johan Hedberg4b580612013-10-19 23:38:21 +03004567 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4568 u8 scan = SCAN_PAGE;
4569 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
4570 sizeof(scan), &scan);
4571 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004572 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004573 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004574 hci_req_run(&req, NULL);
4575
4576 hdev->discov_timeout = 0;
4577
Johan Hedberg9a43e252013-10-20 19:00:07 +03004578 new_settings(hdev, NULL);
4579
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004580 hci_dev_unlock(hdev);
4581}
4582
Marcel Holtmann86a75642013-10-15 06:33:54 -07004583void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004584{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004585 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004586
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004587 /* Nothing needed here if there's a pending command since that
4588 * commands request completion callback takes care of everything
4589 * necessary.
4590 */
4591 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004592 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004593
Johan Hedberg9a43e252013-10-20 19:00:07 +03004594 if (discoverable) {
Marcel Holtmann86a75642013-10-15 06:33:54 -07004595 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004596 } else {
4597 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmann86a75642013-10-15 06:33:54 -07004598 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004599 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004600
Johan Hedberg9a43e252013-10-20 19:00:07 +03004601 if (changed) {
4602 struct hci_request req;
4603
4604 /* In case this change in discoverable was triggered by
4605 * a disabling of connectable there could be a need to
4606 * update the advertising flags.
4607 */
4608 hci_req_init(&req, hdev);
4609 update_adv_data(&req);
4610 hci_req_run(&req, NULL);
4611
Marcel Holtmann86a75642013-10-15 06:33:54 -07004612 new_settings(hdev, NULL);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004613 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004614}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004615
Marcel Holtmanna3309162013-10-15 06:33:55 -07004616void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004617{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004618 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004619
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004620 /* Nothing needed here if there's a pending command since that
4621 * commands request completion callback takes care of everything
4622 * necessary.
4623 */
4624 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004625 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004626
Marcel Holtmanna3309162013-10-15 06:33:55 -07004627 if (connectable)
4628 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4629 else
4630 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004631
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004632 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004633 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004634}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004635
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004636void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004637{
Johan Hedbergca69b792011-11-11 18:10:00 +02004638 u8 mgmt_err = mgmt_status(status);
4639
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004640 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004641 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004642 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004643
4644 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004645 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004646 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004647}
4648
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004649void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4650 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004651{
Johan Hedberg86742e12011-11-07 23:13:38 +02004652 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004653
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004654 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004655
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004656 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004657 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004658 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004659 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004660 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004661 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004662
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004663 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004664}
Johan Hedbergf7520542011-01-20 12:34:39 +02004665
Marcel Holtmann083368f2013-10-15 14:26:29 -07004666void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004667{
4668 struct mgmt_ev_new_long_term_key ev;
4669
4670 memset(&ev, 0, sizeof(ev));
4671
4672 ev.store_hint = persistent;
4673 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004674 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Marcel Holtmannd40f3ee2014-01-31 18:42:17 -08004675 ev.key.type = key->authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004676 ev.key.enc_size = key->enc_size;
4677 ev.key.ediv = key->ediv;
4678
4679 if (key->type == HCI_SMP_LTK)
4680 ev.key.master = 1;
4681
4682 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4683 memcpy(ev.key.val, key->val, sizeof(key->val));
4684
Marcel Holtmann083368f2013-10-15 14:26:29 -07004685 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004686}
4687
Marcel Holtmann94933992013-10-15 10:26:39 -07004688static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4689 u8 data_len)
4690{
4691 eir[eir_len++] = sizeof(type) + data_len;
4692 eir[eir_len++] = type;
4693 memcpy(&eir[eir_len], data, data_len);
4694 eir_len += data_len;
4695
4696 return eir_len;
4697}
4698
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004699void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4700 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4701 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004702{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004703 char buf[512];
4704 struct mgmt_ev_device_connected *ev = (void *) buf;
4705 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004706
Johan Hedbergb644ba32012-01-17 21:48:47 +02004707 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004708 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004709
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004710 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004711
Johan Hedbergb644ba32012-01-17 21:48:47 +02004712 if (name_len > 0)
4713 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004714 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004715
4716 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004717 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004718 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004719
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004720 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004721
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004722 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4723 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004724}
4725
Johan Hedberg8962ee72011-01-20 12:40:27 +02004726static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4727{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004728 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004729 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004730 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004731
Johan Hedberg88c3df12012-02-09 14:27:38 +02004732 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4733 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004734
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004735 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004736 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004737
4738 *sk = cmd->sk;
4739 sock_hold(*sk);
4740
Johan Hedberga664b5b2011-02-19 12:06:02 -03004741 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004742}
4743
Johan Hedberg124f6e32012-02-09 13:50:12 +02004744static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004745{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004746 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004747 struct mgmt_cp_unpair_device *cp = cmd->param;
4748 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004749
4750 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004751 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4752 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004753
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004754 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4755
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004756 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004757
4758 mgmt_pending_remove(cmd);
4759}
4760
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004761void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4762 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004763{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004764 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004765 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004766
Andre Guedes57eb7762013-10-30 19:01:41 -03004767 if (link_type != ACL_LINK && link_type != LE_LINK)
4768 return;
4769
Johan Hedberg744cf192011-11-08 20:40:14 +02004770 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004771
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004772 bacpy(&ev.addr.bdaddr, bdaddr);
4773 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4774 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004775
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004776 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004777
4778 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004779 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004780
Johan Hedberg124f6e32012-02-09 13:50:12 +02004781 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004782 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004783}
4784
Marcel Holtmann78929242013-10-06 23:55:47 -07004785void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4786 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004787{
Andre Guedes3655bba2013-10-30 19:01:40 -03004788 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
4789 struct mgmt_cp_disconnect *cp;
Johan Hedberg88c3df12012-02-09 14:27:38 +02004790 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004791 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004792
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004793 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4794 hdev);
4795
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004796 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004797 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004798 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004799
Andre Guedes3655bba2013-10-30 19:01:40 -03004800 cp = cmd->param;
4801
4802 if (bacmp(bdaddr, &cp->addr.bdaddr))
4803 return;
4804
4805 if (cp->addr.type != bdaddr_type)
4806 return;
4807
Johan Hedberg88c3df12012-02-09 14:27:38 +02004808 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes3655bba2013-10-30 19:01:40 -03004809 rp.addr.type = bdaddr_type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004810
Marcel Holtmann78929242013-10-06 23:55:47 -07004811 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4812 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004813
Johan Hedberga664b5b2011-02-19 12:06:02 -03004814 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004815}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004816
Marcel Holtmann445608d2013-10-06 23:55:48 -07004817void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4818 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004819{
4820 struct mgmt_ev_connect_failed ev;
4821
Johan Hedberg4c659c32011-11-07 23:13:39 +02004822 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004823 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004824 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004825
Marcel Holtmann445608d2013-10-06 23:55:48 -07004826 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004827}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004828
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004829void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004830{
4831 struct mgmt_ev_pin_code_request ev;
4832
Johan Hedbergd8457692012-02-17 14:24:57 +02004833 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004834 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004835 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004836
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004837 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004838}
4839
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004840void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4841 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004842{
4843 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004844 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004845
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004846 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004847 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004848 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004849
Johan Hedbergd8457692012-02-17 14:24:57 +02004850 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004851 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004852
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004853 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
4854 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004855
Johan Hedberga664b5b2011-02-19 12:06:02 -03004856 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004857}
4858
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004859void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4860 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004861{
4862 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004863 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004864
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004865 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004866 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004867 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004868
Johan Hedbergd8457692012-02-17 14:24:57 +02004869 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004870 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004871
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004872 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
4873 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004874
Johan Hedberga664b5b2011-02-19 12:06:02 -03004875 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004876}
Johan Hedberga5c29682011-02-19 12:05:57 -03004877
Johan Hedberg744cf192011-11-08 20:40:14 +02004878int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004879 u8 link_type, u8 addr_type, __le32 value,
4880 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004881{
4882 struct mgmt_ev_user_confirm_request ev;
4883
Johan Hedberg744cf192011-11-08 20:40:14 +02004884 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004885
Johan Hedberg272d90d2012-02-09 15:26:12 +02004886 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004887 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004888 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02004889 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004890
Johan Hedberg744cf192011-11-08 20:40:14 +02004891 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004892 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004893}
4894
Johan Hedberg272d90d2012-02-09 15:26:12 +02004895int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004896 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004897{
4898 struct mgmt_ev_user_passkey_request ev;
4899
4900 BT_DBG("%s", hdev->name);
4901
Johan Hedberg272d90d2012-02-09 15:26:12 +02004902 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004903 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004904
4905 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004906 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004907}
4908
Brian Gix0df4c182011-11-16 13:53:13 -08004909static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004910 u8 link_type, u8 addr_type, u8 status,
4911 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004912{
4913 struct pending_cmd *cmd;
4914 struct mgmt_rp_user_confirm_reply rp;
4915 int err;
4916
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004917 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004918 if (!cmd)
4919 return -ENOENT;
4920
Johan Hedberg272d90d2012-02-09 15:26:12 +02004921 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004922 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004923 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004924 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004925
Johan Hedberga664b5b2011-02-19 12:06:02 -03004926 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004927
4928 return err;
4929}
4930
Johan Hedberg744cf192011-11-08 20:40:14 +02004931int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004932 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004933{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004934 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004935 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004936}
4937
Johan Hedberg272d90d2012-02-09 15:26:12 +02004938int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004939 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004940{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004941 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004942 status,
4943 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004944}
Johan Hedberg2a611692011-02-19 12:06:00 -03004945
Brian Gix604086b2011-11-23 08:28:33 -08004946int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004947 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004948{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004949 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004950 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004951}
4952
Johan Hedberg272d90d2012-02-09 15:26:12 +02004953int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004954 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004955{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004956 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004957 status,
4958 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004959}
4960
Johan Hedberg92a25252012-09-06 18:39:26 +03004961int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4962 u8 link_type, u8 addr_type, u32 passkey,
4963 u8 entered)
4964{
4965 struct mgmt_ev_passkey_notify ev;
4966
4967 BT_DBG("%s", hdev->name);
4968
4969 bacpy(&ev.addr.bdaddr, bdaddr);
4970 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4971 ev.passkey = __cpu_to_le32(passkey);
4972 ev.entered = entered;
4973
4974 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4975}
4976
Marcel Holtmanne5460992013-10-15 14:26:23 -07004977void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4978 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004979{
4980 struct mgmt_ev_auth_failed ev;
4981
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004982 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004983 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004984 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004985
Marcel Holtmanne5460992013-10-15 14:26:23 -07004986 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004987}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004988
Marcel Holtmann464996a2013-10-15 14:26:24 -07004989void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004990{
4991 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07004992 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004993
4994 if (status) {
4995 u8 mgmt_err = mgmt_status(status);
4996 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004997 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07004998 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004999 }
5000
Marcel Holtmann464996a2013-10-15 14:26:24 -07005001 if (test_bit(HCI_AUTH, &hdev->flags))
5002 changed = !test_and_set_bit(HCI_LINK_SECURITY,
5003 &hdev->dev_flags);
5004 else
5005 changed = test_and_clear_bit(HCI_LINK_SECURITY,
5006 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02005007
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005008 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005009 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005010
Johan Hedberg47990ea2012-02-22 11:58:37 +02005011 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07005012 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005013
5014 if (match.sk)
5015 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005016}
5017
Johan Hedberg890ea892013-03-15 17:06:52 -05005018static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02005019{
Johan Hedberg890ea892013-03-15 17:06:52 -05005020 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02005021 struct hci_cp_write_eir cp;
5022
Johan Hedberg976eb202012-10-24 21:12:01 +03005023 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05005024 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02005025
Johan Hedbergc80da272012-02-22 15:38:48 +02005026 memset(hdev->eir, 0, sizeof(hdev->eir));
5027
Johan Hedbergcacaf522012-02-21 00:52:42 +02005028 memset(&cp, 0, sizeof(cp));
5029
Johan Hedberg890ea892013-03-15 17:06:52 -05005030 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02005031}
5032
Marcel Holtmann3e248562013-10-15 14:26:25 -07005033void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005034{
5035 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05005036 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005037 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005038
5039 if (status) {
5040 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005041
5042 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005043 &hdev->dev_flags)) {
5044 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07005045 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005046 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005047
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005048 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
5049 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07005050 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005051 }
5052
5053 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005054 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005055 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005056 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
5057 if (!changed)
5058 changed = test_and_clear_bit(HCI_HS_ENABLED,
5059 &hdev->dev_flags);
5060 else
5061 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005062 }
5063
5064 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
5065
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005066 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07005067 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005068
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005069 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005070 sock_put(match.sk);
5071
Johan Hedberg890ea892013-03-15 17:06:52 -05005072 hci_req_init(&req, hdev);
5073
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005074 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05005075 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005076 else
Johan Hedberg890ea892013-03-15 17:06:52 -05005077 clear_eir(&req);
5078
5079 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005080}
5081
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005082void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
5083{
5084 struct cmd_lookup match = { NULL, hdev };
5085 bool changed = false;
5086
5087 if (status) {
5088 u8 mgmt_err = mgmt_status(status);
5089
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005090 if (enable) {
5091 if (test_and_clear_bit(HCI_SC_ENABLED,
5092 &hdev->dev_flags))
5093 new_settings(hdev, NULL);
5094 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
5095 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005096
5097 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5098 cmd_status_rsp, &mgmt_err);
5099 return;
5100 }
5101
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005102 if (enable) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005103 changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005104 } else {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005105 changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005106 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
5107 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005108
5109 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5110 settings_rsp, &match);
5111
5112 if (changed)
5113 new_settings(hdev, match.sk);
5114
5115 if (match.sk)
5116 sock_put(match.sk);
5117}
5118
Johan Hedberg92da6092013-03-15 17:06:55 -05005119static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02005120{
5121 struct cmd_lookup *match = data;
5122
Johan Hedberg90e70452012-02-23 23:09:40 +02005123 if (match->sk == NULL) {
5124 match->sk = cmd->sk;
5125 sock_hold(match->sk);
5126 }
Johan Hedberg90e70452012-02-23 23:09:40 +02005127}
5128
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005129void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
5130 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005131{
Johan Hedberg90e70452012-02-23 23:09:40 +02005132 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005133
Johan Hedberg92da6092013-03-15 17:06:55 -05005134 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
5135 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
5136 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02005137
5138 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005139 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
5140 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02005141
5142 if (match.sk)
5143 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005144}
5145
Marcel Holtmann7667da32013-10-15 14:26:27 -07005146void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02005147{
Johan Hedbergb312b1612011-03-16 14:29:37 +02005148 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05005149 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005150
Johan Hedberg13928972013-03-15 17:07:00 -05005151 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07005152 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005153
5154 memset(&ev, 0, sizeof(ev));
5155 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005156 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005157
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005158 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05005159 if (!cmd) {
5160 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02005161
Johan Hedberg13928972013-03-15 17:07:00 -05005162 /* If this is a HCI command related to powering on the
5163 * HCI dev don't send any mgmt signals.
5164 */
5165 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07005166 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005167 }
5168
Marcel Holtmann7667da32013-10-15 14:26:27 -07005169 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
5170 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005171}
Szymon Jancc35938b2011-03-22 13:12:21 +01005172
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005173void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
5174 u8 *randomizer192, u8 *hash256,
5175 u8 *randomizer256, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01005176{
5177 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01005178
Johan Hedberg744cf192011-11-08 20:40:14 +02005179 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01005180
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005181 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01005182 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005183 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01005184
5185 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005186 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
5187 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01005188 } else {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005189 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
5190 hash256 && randomizer256) {
5191 struct mgmt_rp_read_local_oob_ext_data rp;
Szymon Jancc35938b2011-03-22 13:12:21 +01005192
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005193 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
5194 memcpy(rp.randomizer192, randomizer192,
5195 sizeof(rp.randomizer192));
Szymon Jancc35938b2011-03-22 13:12:21 +01005196
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005197 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
5198 memcpy(rp.randomizer256, randomizer256,
5199 sizeof(rp.randomizer256));
5200
5201 cmd_complete(cmd->sk, hdev->id,
5202 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5203 &rp, sizeof(rp));
5204 } else {
5205 struct mgmt_rp_read_local_oob_data rp;
5206
5207 memcpy(rp.hash, hash192, sizeof(rp.hash));
5208 memcpy(rp.randomizer, randomizer192,
5209 sizeof(rp.randomizer));
5210
5211 cmd_complete(cmd->sk, hdev->id,
5212 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5213 &rp, sizeof(rp));
5214 }
Szymon Jancc35938b2011-03-22 13:12:21 +01005215 }
5216
5217 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01005218}
Johan Hedberge17acd42011-03-30 23:57:16 +03005219
Marcel Holtmann901801b2013-10-06 23:55:51 -07005220void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5221 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
5222 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03005223{
Johan Hedberge319d2e2012-01-15 19:51:59 +02005224 char buf[512];
5225 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02005226 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03005227
Andre Guedes12602d02013-04-30 15:29:40 -03005228 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005229 return;
Andre Guedes12602d02013-04-30 15:29:40 -03005230
Johan Hedberg1dc06092012-01-15 21:01:23 +02005231 /* Leave 5 bytes for a potential CoD field */
5232 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005233 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03005234
Johan Hedberg1dc06092012-01-15 21:01:23 +02005235 memset(buf, 0, sizeof(buf));
5236
Johan Hedberge319d2e2012-01-15 19:51:59 +02005237 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005238 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02005239 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02005240 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305241 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02005242 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305243 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03005244
Johan Hedberg1dc06092012-01-15 21:01:23 +02005245 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02005246 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03005247
Johan Hedberg1dc06092012-01-15 21:01:23 +02005248 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
5249 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005250 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005251
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005252 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005253 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03005254
Marcel Holtmann901801b2013-10-06 23:55:51 -07005255 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03005256}
Johan Hedberga88a9652011-03-30 13:18:12 +03005257
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005258void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5259 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03005260{
Johan Hedbergb644ba32012-01-17 21:48:47 +02005261 struct mgmt_ev_device_found *ev;
5262 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
5263 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03005264
Johan Hedbergb644ba32012-01-17 21:48:47 +02005265 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03005266
Johan Hedbergb644ba32012-01-17 21:48:47 +02005267 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03005268
Johan Hedbergb644ba32012-01-17 21:48:47 +02005269 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005270 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005271 ev->rssi = rssi;
5272
5273 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005274 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005275
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005276 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005277
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005278 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03005279}
Johan Hedberg314b2382011-04-27 10:29:57 -04005280
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005281void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04005282{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005283 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02005284 struct pending_cmd *cmd;
5285
Andre Guedes343fb142011-11-22 17:14:19 -03005286 BT_DBG("%s discovering %u", hdev->name, discovering);
5287
Johan Hedberg164a6e72011-11-01 17:06:44 +02005288 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005289 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005290 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005291 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005292
5293 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02005294 u8 type = hdev->discovery.type;
5295
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005296 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
5297 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02005298 mgmt_pending_remove(cmd);
5299 }
5300
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005301 memset(&ev, 0, sizeof(ev));
5302 ev.type = hdev->discovery.type;
5303 ev.discovering = discovering;
5304
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005305 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04005306}
Antti Julku5e762442011-08-25 16:48:02 +03005307
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005308int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005309{
5310 struct pending_cmd *cmd;
5311 struct mgmt_ev_device_blocked ev;
5312
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005313 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005314
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005315 bacpy(&ev.addr.bdaddr, bdaddr);
5316 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005317
Johan Hedberg744cf192011-11-08 20:40:14 +02005318 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005319 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005320}
5321
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005322int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005323{
5324 struct pending_cmd *cmd;
5325 struct mgmt_ev_device_unblocked ev;
5326
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005327 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005328
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005329 bacpy(&ev.addr.bdaddr, bdaddr);
5330 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005331
Johan Hedberg744cf192011-11-08 20:40:14 +02005332 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005333 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005334}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005335
5336static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5337{
5338 BT_DBG("%s status %u", hdev->name, status);
5339
5340 /* Clear the advertising mgmt setting if we failed to re-enable it */
5341 if (status) {
5342 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005343 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005344 }
5345}
5346
5347void mgmt_reenable_advertising(struct hci_dev *hdev)
5348{
5349 struct hci_request req;
5350
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005351 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005352 return;
5353
5354 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5355 return;
5356
5357 hci_req_init(&req, hdev);
5358 enable_advertising(&req);
5359
5360 /* If this fails we have no option but to let user space know
5361 * that we've disabled advertising.
5362 */
5363 if (hci_req_run(&req, adv_enable_complete) < 0) {
5364 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005365 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005366 }
5367}