blob: bc329d911706a2fccec32da301363b242a8aa426 [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 Holtmann40456642014-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 Hedberg41edf162014-02-18 10:19:35 +020084 MGMT_OP_LOAD_IRKS,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020085};
86
87static const u16 mgmt_events[] = {
88 MGMT_EV_CONTROLLER_ERROR,
89 MGMT_EV_INDEX_ADDED,
90 MGMT_EV_INDEX_REMOVED,
91 MGMT_EV_NEW_SETTINGS,
92 MGMT_EV_CLASS_OF_DEV_CHANGED,
93 MGMT_EV_LOCAL_NAME_CHANGED,
94 MGMT_EV_NEW_LINK_KEY,
95 MGMT_EV_NEW_LONG_TERM_KEY,
96 MGMT_EV_DEVICE_CONNECTED,
97 MGMT_EV_DEVICE_DISCONNECTED,
98 MGMT_EV_CONNECT_FAILED,
99 MGMT_EV_PIN_CODE_REQUEST,
100 MGMT_EV_USER_CONFIRM_REQUEST,
101 MGMT_EV_USER_PASSKEY_REQUEST,
102 MGMT_EV_AUTH_FAILED,
103 MGMT_EV_DEVICE_FOUND,
104 MGMT_EV_DISCOVERING,
105 MGMT_EV_DEVICE_BLOCKED,
106 MGMT_EV_DEVICE_UNBLOCKED,
107 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300108 MGMT_EV_PASSKEY_NOTIFY,
Marcel Holtmann1b60ef22014-02-21 21:35:30 -0800109 MGMT_EV_NEW_IRK,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200110};
111
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800112#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200113
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200114#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
115 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
116
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200117struct pending_cmd {
118 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200119 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200120 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100121 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200122 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300123 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124};
125
Johan Hedbergca69b792011-11-11 18:10:00 +0200126/* HCI to MGMT error code conversion table */
127static u8 mgmt_status_table[] = {
128 MGMT_STATUS_SUCCESS,
129 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
130 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
131 MGMT_STATUS_FAILED, /* Hardware Failure */
132 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
133 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200134 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200135 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
136 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
137 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
138 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
139 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
140 MGMT_STATUS_BUSY, /* Command Disallowed */
141 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
142 MGMT_STATUS_REJECTED, /* Rejected Security */
143 MGMT_STATUS_REJECTED, /* Rejected Personal */
144 MGMT_STATUS_TIMEOUT, /* Host Timeout */
145 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
146 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
147 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
148 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
149 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
150 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
151 MGMT_STATUS_BUSY, /* Repeated Attempts */
152 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
153 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
154 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
155 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
156 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
157 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
158 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
159 MGMT_STATUS_FAILED, /* Unspecified Error */
160 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
161 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
162 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
163 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
164 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
165 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
166 MGMT_STATUS_FAILED, /* Unit Link Key Used */
167 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
168 MGMT_STATUS_TIMEOUT, /* Instant Passed */
169 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
170 MGMT_STATUS_FAILED, /* Transaction Collision */
171 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
172 MGMT_STATUS_REJECTED, /* QoS Rejected */
173 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
174 MGMT_STATUS_REJECTED, /* Insufficient Security */
175 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
176 MGMT_STATUS_BUSY, /* Role Switch Pending */
177 MGMT_STATUS_FAILED, /* Slot Violation */
178 MGMT_STATUS_FAILED, /* Role Switch Failed */
179 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
180 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
181 MGMT_STATUS_BUSY, /* Host Busy Pairing */
182 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
183 MGMT_STATUS_BUSY, /* Controller Busy */
184 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
185 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
186 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
187 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
188 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
189};
190
191static u8 mgmt_status(u8 hci_status)
192{
193 if (hci_status < ARRAY_SIZE(mgmt_status_table))
194 return mgmt_status_table[hci_status];
195
196 return MGMT_STATUS_FAILED;
197}
198
Szymon Janc4e51eae2011-02-25 19:05:48 +0100199static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200200{
201 struct sk_buff *skb;
202 struct mgmt_hdr *hdr;
203 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300204 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200205
Szymon Janc34eb5252011-02-28 14:10:08 +0100206 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200207
Andre Guedes790eff42012-06-07 19:05:46 -0300208 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200209 if (!skb)
210 return -ENOMEM;
211
212 hdr = (void *) skb_put(skb, sizeof(*hdr));
213
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530214 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100215 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200216 hdr->len = cpu_to_le16(sizeof(*ev));
217
218 ev = (void *) skb_put(skb, sizeof(*ev));
219 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200220 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200221
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300222 err = sock_queue_rcv_skb(sk, skb);
223 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200224 kfree_skb(skb);
225
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300226 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200227}
228
Johan Hedbergaee9b212012-02-18 15:07:59 +0200229static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300230 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200231{
232 struct sk_buff *skb;
233 struct mgmt_hdr *hdr;
234 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300235 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200236
237 BT_DBG("sock %p", sk);
238
Andre Guedes790eff42012-06-07 19:05:46 -0300239 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200240 if (!skb)
241 return -ENOMEM;
242
243 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200244
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530245 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100246 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200247 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200248
Johan Hedberga38528f2011-01-22 06:46:43 +0200249 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200250 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200251 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100252
253 if (rp)
254 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200255
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300256 err = sock_queue_rcv_skb(sk, skb);
257 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200258 kfree_skb(skb);
259
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100260 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200261}
262
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300263static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
264 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200265{
266 struct mgmt_rp_read_version rp;
267
268 BT_DBG("sock %p", sk);
269
270 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200271 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200272
Johan Hedbergaee9b212012-02-18 15:07:59 +0200273 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300274 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200275}
276
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300277static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
278 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200279{
280 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200281 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
282 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200283 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200284 size_t rp_size;
285 int i, err;
286
287 BT_DBG("sock %p", sk);
288
289 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
290
291 rp = kmalloc(rp_size, GFP_KERNEL);
292 if (!rp)
293 return -ENOMEM;
294
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200295 rp->num_commands = __constant_cpu_to_le16(num_commands);
296 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200297
298 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
299 put_unaligned_le16(mgmt_commands[i], opcode);
300
301 for (i = 0; i < num_events; i++, opcode++)
302 put_unaligned_le16(mgmt_events[i], opcode);
303
Johan Hedbergaee9b212012-02-18 15:07:59 +0200304 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300305 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200306 kfree(rp);
307
308 return err;
309}
310
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300311static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
312 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200314 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200315 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200316 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200317 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300318 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200319
320 BT_DBG("sock %p", sk);
321
322 read_lock(&hci_dev_list_lock);
323
324 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300325 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700326 if (d->dev_type == HCI_BREDR)
327 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200328 }
329
Johan Hedberga38528f2011-01-22 06:46:43 +0200330 rp_len = sizeof(*rp) + (2 * count);
331 rp = kmalloc(rp_len, GFP_ATOMIC);
332 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100333 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200334 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100335 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200336
Johan Hedberg476e44c2012-10-19 20:10:46 +0300337 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200338 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200339 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200340 continue;
341
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700342 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
343 continue;
344
Marcel Holtmann1514b892013-10-06 08:25:01 -0700345 if (d->dev_type == HCI_BREDR) {
346 rp->index[count++] = cpu_to_le16(d->id);
347 BT_DBG("Added hci%u", d->id);
348 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349 }
350
Johan Hedberg476e44c2012-10-19 20:10:46 +0300351 rp->num_controllers = cpu_to_le16(count);
352 rp_len = sizeof(*rp) + (2 * count);
353
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354 read_unlock(&hci_dev_list_lock);
355
Johan Hedbergaee9b212012-02-18 15:07:59 +0200356 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300357 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200358
Johan Hedberga38528f2011-01-22 06:46:43 +0200359 kfree(rp);
360
361 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200362}
363
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200365{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200367
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200368 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200369 settings |= MGMT_SETTING_PAIRABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800370 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Andre Guedesed3fa312012-07-24 15:03:46 -0300372 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300373 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500374 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
375 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300376 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200377 settings |= MGMT_SETTING_BREDR;
378 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700379
380 if (lmp_ssp_capable(hdev)) {
381 settings |= MGMT_SETTING_SSP;
382 settings |= MGMT_SETTING_HS;
383 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800384
Marcel Holtmann5afeac12014-01-10 02:07:27 -0800385 if (lmp_sc_capable(hdev) ||
386 test_bit(HCI_FORCE_SC, &hdev->dev_flags))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800387 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700388 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100389
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300390 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200391 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300392 settings |= MGMT_SETTING_ADVERTISING;
393 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200394
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200395 return settings;
396}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200397
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200398static u32 get_current_settings(struct hci_dev *hdev)
399{
400 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200401
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200402 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100403 settings |= MGMT_SETTING_POWERED;
404
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200405 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200406 settings |= MGMT_SETTING_CONNECTABLE;
407
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500408 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
409 settings |= MGMT_SETTING_FAST_CONNECTABLE;
410
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200411 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200412 settings |= MGMT_SETTING_DISCOVERABLE;
413
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200414 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_PAIRABLE;
416
Johan Hedberg56f87902013-10-02 13:43:13 +0300417 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200418 settings |= MGMT_SETTING_BREDR;
419
Johan Hedberg06199cf2012-02-22 16:37:11 +0200420 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200421 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200422
Johan Hedberg47990ea2012-02-22 11:58:37 +0200423 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200424 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200425
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200426 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200427 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200428
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200429 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
430 settings |= MGMT_SETTING_HS;
431
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200432 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300433 settings |= MGMT_SETTING_ADVERTISING;
434
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800435 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
436 settings |= MGMT_SETTING_SECURE_CONN;
437
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800438 if (test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags))
439 settings |= MGMT_SETTING_DEBUG_KEYS;
440
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200441 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200442}
443
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300444#define PNP_INFO_SVCLASS_ID 0x1200
445
Johan Hedberg213202e2013-01-27 00:31:33 +0200446static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
447{
448 u8 *ptr = data, *uuids_start = NULL;
449 struct bt_uuid *uuid;
450
451 if (len < 4)
452 return ptr;
453
454 list_for_each_entry(uuid, &hdev->uuids, list) {
455 u16 uuid16;
456
457 if (uuid->size != 16)
458 continue;
459
460 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
461 if (uuid16 < 0x1100)
462 continue;
463
464 if (uuid16 == PNP_INFO_SVCLASS_ID)
465 continue;
466
467 if (!uuids_start) {
468 uuids_start = ptr;
469 uuids_start[0] = 1;
470 uuids_start[1] = EIR_UUID16_ALL;
471 ptr += 2;
472 }
473
474 /* Stop if not enough space to put next UUID */
475 if ((ptr - data) + sizeof(u16) > len) {
476 uuids_start[1] = EIR_UUID16_SOME;
477 break;
478 }
479
480 *ptr++ = (uuid16 & 0x00ff);
481 *ptr++ = (uuid16 & 0xff00) >> 8;
482 uuids_start[0] += sizeof(uuid16);
483 }
484
485 return ptr;
486}
487
Johan Hedbergcdf19632013-01-27 00:31:34 +0200488static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
489{
490 u8 *ptr = data, *uuids_start = NULL;
491 struct bt_uuid *uuid;
492
493 if (len < 6)
494 return ptr;
495
496 list_for_each_entry(uuid, &hdev->uuids, list) {
497 if (uuid->size != 32)
498 continue;
499
500 if (!uuids_start) {
501 uuids_start = ptr;
502 uuids_start[0] = 1;
503 uuids_start[1] = EIR_UUID32_ALL;
504 ptr += 2;
505 }
506
507 /* Stop if not enough space to put next UUID */
508 if ((ptr - data) + sizeof(u32) > len) {
509 uuids_start[1] = EIR_UUID32_SOME;
510 break;
511 }
512
513 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
514 ptr += sizeof(u32);
515 uuids_start[0] += sizeof(u32);
516 }
517
518 return ptr;
519}
520
Johan Hedbergc00d5752013-01-27 00:31:35 +0200521static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
522{
523 u8 *ptr = data, *uuids_start = NULL;
524 struct bt_uuid *uuid;
525
526 if (len < 18)
527 return ptr;
528
529 list_for_each_entry(uuid, &hdev->uuids, list) {
530 if (uuid->size != 128)
531 continue;
532
533 if (!uuids_start) {
534 uuids_start = ptr;
535 uuids_start[0] = 1;
536 uuids_start[1] = EIR_UUID128_ALL;
537 ptr += 2;
538 }
539
540 /* Stop if not enough space to put next UUID */
541 if ((ptr - data) + 16 > len) {
542 uuids_start[1] = EIR_UUID128_SOME;
543 break;
544 }
545
546 memcpy(ptr, uuid->uuid, 16);
547 ptr += 16;
548 uuids_start[0] += 16;
549 }
550
551 return ptr;
552}
553
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300554static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
555{
556 struct pending_cmd *cmd;
557
558 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
559 if (cmd->opcode == opcode)
560 return cmd;
561 }
562
563 return NULL;
564}
565
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700566static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
567{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700568 u8 ad_len = 0;
569 size_t name_len;
570
571 name_len = strlen(hdev->dev_name);
572 if (name_len > 0) {
573 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
574
575 if (name_len > max_len) {
576 name_len = max_len;
577 ptr[1] = EIR_NAME_SHORT;
578 } else
579 ptr[1] = EIR_NAME_COMPLETE;
580
581 ptr[0] = name_len + 1;
582
583 memcpy(ptr + 2, hdev->dev_name, name_len);
584
585 ad_len += (name_len + 2);
586 ptr += (name_len + 2);
587 }
588
589 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700590}
591
592static void update_scan_rsp_data(struct hci_request *req)
593{
594 struct hci_dev *hdev = req->hdev;
595 struct hci_cp_le_set_scan_rsp_data cp;
596 u8 len;
597
Johan Hedberg7751ef12013-10-19 23:38:15 +0300598 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700599 return;
600
601 memset(&cp, 0, sizeof(cp));
602
603 len = create_scan_rsp_data(hdev, cp.data);
604
Johan Hedbergeb438b52013-10-16 15:31:07 +0300605 if (hdev->scan_rsp_data_len == len &&
606 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700607 return;
608
Johan Hedbergeb438b52013-10-16 15:31:07 +0300609 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
610 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700611
612 cp.length = len;
613
614 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
615}
616
Johan Hedberg9a43e252013-10-20 19:00:07 +0300617static u8 get_adv_discov_flags(struct hci_dev *hdev)
618{
619 struct pending_cmd *cmd;
620
621 /* If there's a pending mgmt command the flags will not yet have
622 * their final values, so check for this first.
623 */
624 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
625 if (cmd) {
626 struct mgmt_mode *cp = cmd->param;
627 if (cp->val == 0x01)
628 return LE_AD_GENERAL;
629 else if (cp->val == 0x02)
630 return LE_AD_LIMITED;
631 } else {
632 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
633 return LE_AD_LIMITED;
634 else if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
635 return LE_AD_GENERAL;
636 }
637
638 return 0;
639}
640
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700641static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700642{
643 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700644
Johan Hedberg9a43e252013-10-20 19:00:07 +0300645 flags |= get_adv_discov_flags(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700646
Johan Hedberge8340042014-01-30 11:16:50 -0800647 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700648 flags |= LE_AD_NO_BREDR;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700649
650 if (flags) {
651 BT_DBG("adv flags 0x%02x", flags);
652
653 ptr[0] = 2;
654 ptr[1] = EIR_FLAGS;
655 ptr[2] = flags;
656
657 ad_len += 3;
658 ptr += 3;
659 }
660
661 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
662 ptr[0] = 2;
663 ptr[1] = EIR_TX_POWER;
664 ptr[2] = (u8) hdev->adv_tx_power;
665
666 ad_len += 3;
667 ptr += 3;
668 }
669
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700670 return ad_len;
671}
672
Marcel Holtmann5947f4b2013-10-16 00:16:50 -0700673static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700674{
675 struct hci_dev *hdev = req->hdev;
676 struct hci_cp_le_set_adv_data cp;
677 u8 len;
678
Johan Hedberg10994ce2013-10-19 23:38:16 +0300679 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700680 return;
681
682 memset(&cp, 0, sizeof(cp));
683
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700684 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700685
686 if (hdev->adv_data_len == len &&
687 memcmp(cp.data, hdev->adv_data, len) == 0)
688 return;
689
690 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
691 hdev->adv_data_len = len;
692
693 cp.length = len;
694
695 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
696}
697
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300698static void create_eir(struct hci_dev *hdev, u8 *data)
699{
700 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300701 size_t name_len;
702
703 name_len = strlen(hdev->dev_name);
704
705 if (name_len > 0) {
706 /* EIR Data type */
707 if (name_len > 48) {
708 name_len = 48;
709 ptr[1] = EIR_NAME_SHORT;
710 } else
711 ptr[1] = EIR_NAME_COMPLETE;
712
713 /* EIR Data length */
714 ptr[0] = name_len + 1;
715
716 memcpy(ptr + 2, hdev->dev_name, name_len);
717
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300718 ptr += (name_len + 2);
719 }
720
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100721 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700722 ptr[0] = 2;
723 ptr[1] = EIR_TX_POWER;
724 ptr[2] = (u8) hdev->inq_tx_power;
725
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700726 ptr += 3;
727 }
728
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700729 if (hdev->devid_source > 0) {
730 ptr[0] = 9;
731 ptr[1] = EIR_DEVICE_ID;
732
733 put_unaligned_le16(hdev->devid_source, ptr + 2);
734 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
735 put_unaligned_le16(hdev->devid_product, ptr + 6);
736 put_unaligned_le16(hdev->devid_version, ptr + 8);
737
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700738 ptr += 10;
739 }
740
Johan Hedberg213202e2013-01-27 00:31:33 +0200741 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200742 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200743 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300744}
745
Johan Hedberg890ea892013-03-15 17:06:52 -0500746static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300747{
Johan Hedberg890ea892013-03-15 17:06:52 -0500748 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300749 struct hci_cp_write_eir cp;
750
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200751 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500752 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200753
Johan Hedberg976eb202012-10-24 21:12:01 +0300754 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500755 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300756
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200757 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500758 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300759
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200760 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500761 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300762
763 memset(&cp, 0, sizeof(cp));
764
765 create_eir(hdev, cp.data);
766
767 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500768 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300769
770 memcpy(hdev->eir, cp.data, sizeof(cp.data));
771
Johan Hedberg890ea892013-03-15 17:06:52 -0500772 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300773}
774
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200775static u8 get_service_classes(struct hci_dev *hdev)
776{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300777 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200778 u8 val = 0;
779
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300780 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200781 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200782
783 return val;
784}
785
Johan Hedberg890ea892013-03-15 17:06:52 -0500786static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200787{
Johan Hedberg890ea892013-03-15 17:06:52 -0500788 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200789 u8 cod[3];
790
791 BT_DBG("%s", hdev->name);
792
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200793 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500794 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200795
Johan Hedbergf87ea1d2013-10-19 23:38:17 +0300796 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
797 return;
798
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200799 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500800 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200801
802 cod[0] = hdev->minor_class;
803 cod[1] = hdev->major_class;
804 cod[2] = get_service_classes(hdev);
805
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700806 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
807 cod[1] |= 0x20;
808
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200809 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500810 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200811
Johan Hedberg890ea892013-03-15 17:06:52 -0500812 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200813}
814
Johan Hedberg7d785252011-12-15 00:47:39 +0200815static void service_cache_off(struct work_struct *work)
816{
817 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300818 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500819 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200820
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200821 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200822 return;
823
Johan Hedberg890ea892013-03-15 17:06:52 -0500824 hci_req_init(&req, hdev);
825
Johan Hedberg7d785252011-12-15 00:47:39 +0200826 hci_dev_lock(hdev);
827
Johan Hedberg890ea892013-03-15 17:06:52 -0500828 update_eir(&req);
829 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200830
831 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500832
833 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200834}
835
Johan Hedberg6a919082012-02-28 06:17:26 +0200836static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200837{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200838 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200839 return;
840
Johan Hedberg4f87da82012-03-02 19:55:56 +0200841 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200842
Johan Hedberg4f87da82012-03-02 19:55:56 +0200843 /* Non-mgmt controlled devices get this bit set
844 * implicitly so that pairing works for them, however
845 * for mgmt we require user-space to explicitly enable
846 * it
847 */
848 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200849}
850
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200851static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300852 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200853{
854 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200855
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200856 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200857
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300858 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200859
Johan Hedberg03811012010-12-08 00:21:06 +0200860 memset(&rp, 0, sizeof(rp));
861
Johan Hedberg03811012010-12-08 00:21:06 +0200862 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200863
864 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200865 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200866
867 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
868 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
869
870 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200871
872 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200873 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200874
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300875 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200876
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200877 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300878 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200879}
880
881static void mgmt_pending_free(struct pending_cmd *cmd)
882{
883 sock_put(cmd->sk);
884 kfree(cmd->param);
885 kfree(cmd);
886}
887
888static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300889 struct hci_dev *hdev, void *data,
890 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200891{
892 struct pending_cmd *cmd;
893
Andre Guedes12b94562012-06-07 19:05:45 -0300894 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200895 if (!cmd)
896 return NULL;
897
898 cmd->opcode = opcode;
899 cmd->index = hdev->id;
900
Andre Guedes12b94562012-06-07 19:05:45 -0300901 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200902 if (!cmd->param) {
903 kfree(cmd);
904 return NULL;
905 }
906
907 if (data)
908 memcpy(cmd->param, data, len);
909
910 cmd->sk = sk;
911 sock_hold(sk);
912
913 list_add(&cmd->list, &hdev->mgmt_pending);
914
915 return cmd;
916}
917
918static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300919 void (*cb)(struct pending_cmd *cmd,
920 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300921 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200922{
Andre Guedesa3d09352013-02-01 11:21:30 -0300923 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200924
Andre Guedesa3d09352013-02-01 11:21:30 -0300925 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200926 if (opcode > 0 && cmd->opcode != opcode)
927 continue;
928
929 cb(cmd, data);
930 }
931}
932
Johan Hedberg03811012010-12-08 00:21:06 +0200933static void mgmt_pending_remove(struct pending_cmd *cmd)
934{
935 list_del(&cmd->list);
936 mgmt_pending_free(cmd);
937}
938
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200939static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200940{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200941 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200942
Johan Hedbergaee9b212012-02-18 15:07:59 +0200943 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300944 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200945}
946
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200947static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300948 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200949{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300950 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200951 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200952 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200953
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200954 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200955
Johan Hedberga7e80f22013-01-09 16:05:19 +0200956 if (cp->val != 0x00 && cp->val != 0x01)
957 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
958 MGMT_STATUS_INVALID_PARAMS);
959
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300960 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200961
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300962 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
963 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
964 MGMT_STATUS_BUSY);
965 goto failed;
966 }
967
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100968 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
969 cancel_delayed_work(&hdev->power_off);
970
971 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200972 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
973 data, len);
974 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100975 goto failed;
976 }
977 }
978
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200979 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200980 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200981 goto failed;
982 }
983
Johan Hedberg03811012010-12-08 00:21:06 +0200984 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
985 if (!cmd) {
986 err = -ENOMEM;
987 goto failed;
988 }
989
990 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200991 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200992 else
Johan Hedberg19202572013-01-14 22:33:51 +0200993 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200994
995 err = 0;
996
997failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300998 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200999 return err;
1000}
1001
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001002static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
1003 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001004{
1005 struct sk_buff *skb;
1006 struct mgmt_hdr *hdr;
1007
Andre Guedes790eff42012-06-07 19:05:46 -03001008 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001009 if (!skb)
1010 return -ENOMEM;
1011
1012 hdr = (void *) skb_put(skb, sizeof(*hdr));
1013 hdr->opcode = cpu_to_le16(event);
1014 if (hdev)
1015 hdr->index = cpu_to_le16(hdev->id);
1016 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05301017 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001018 hdr->len = cpu_to_le16(data_len);
1019
1020 if (data)
1021 memcpy(skb_put(skb, data_len), data, data_len);
1022
Marcel Holtmann97e0bde2012-02-22 13:49:28 +01001023 /* Time stamp */
1024 __net_timestamp(skb);
1025
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001026 hci_send_to_control(skb, skip_sk);
1027 kfree_skb(skb);
1028
1029 return 0;
1030}
1031
1032static int new_settings(struct hci_dev *hdev, struct sock *skip)
1033{
1034 __le32 ev;
1035
1036 ev = cpu_to_le32(get_current_settings(hdev));
1037
1038 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1039}
1040
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001041struct cmd_lookup {
1042 struct sock *sk;
1043 struct hci_dev *hdev;
1044 u8 mgmt_status;
1045};
1046
1047static void settings_rsp(struct pending_cmd *cmd, void *data)
1048{
1049 struct cmd_lookup *match = data;
1050
1051 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1052
1053 list_del(&cmd->list);
1054
1055 if (match->sk == NULL) {
1056 match->sk = cmd->sk;
1057 sock_hold(match->sk);
1058 }
1059
1060 mgmt_pending_free(cmd);
1061}
1062
1063static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1064{
1065 u8 *status = data;
1066
1067 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1068 mgmt_pending_remove(cmd);
1069}
1070
Johan Hedberge6fe7982013-10-02 15:45:22 +03001071static u8 mgmt_bredr_support(struct hci_dev *hdev)
1072{
1073 if (!lmp_bredr_capable(hdev))
1074 return MGMT_STATUS_NOT_SUPPORTED;
1075 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1076 return MGMT_STATUS_REJECTED;
1077 else
1078 return MGMT_STATUS_SUCCESS;
1079}
1080
1081static u8 mgmt_le_support(struct hci_dev *hdev)
1082{
1083 if (!lmp_le_capable(hdev))
1084 return MGMT_STATUS_NOT_SUPPORTED;
1085 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1086 return MGMT_STATUS_REJECTED;
1087 else
1088 return MGMT_STATUS_SUCCESS;
1089}
1090
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001091static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1092{
1093 struct pending_cmd *cmd;
1094 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001095 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001096 bool changed;
1097
1098 BT_DBG("status 0x%02x", status);
1099
1100 hci_dev_lock(hdev);
1101
1102 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1103 if (!cmd)
1104 goto unlock;
1105
1106 if (status) {
1107 u8 mgmt_err = mgmt_status(status);
1108 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001109 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001110 goto remove_cmd;
1111 }
1112
1113 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001114 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001115 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1116 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001117
1118 if (hdev->discov_timeout > 0) {
1119 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1120 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1121 to);
1122 }
1123 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001124 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1125 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001126 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001127
1128 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1129
1130 if (changed)
1131 new_settings(hdev, cmd->sk);
1132
Marcel Holtmann970ba522013-10-15 06:33:57 -07001133 /* When the discoverable mode gets changed, make sure
1134 * that class of device has the limited discoverable
1135 * bit correctly set.
1136 */
1137 hci_req_init(&req, hdev);
1138 update_class(&req);
1139 hci_req_run(&req, NULL);
1140
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001141remove_cmd:
1142 mgmt_pending_remove(cmd);
1143
1144unlock:
1145 hci_dev_unlock(hdev);
1146}
1147
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001148static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001149 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001150{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001151 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001152 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001153 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001154 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001155 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001156 int err;
1157
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001158 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001159
Johan Hedberg9a43e252013-10-20 19:00:07 +03001160 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1161 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001162 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberg9a43e252013-10-20 19:00:07 +03001163 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001164
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001165 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga7e80f22013-01-09 16:05:19 +02001166 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1167 MGMT_STATUS_INVALID_PARAMS);
1168
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001169 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001170
1171 /* Disabling discoverable requires that no timeout is set,
1172 * and enabling limited discoverable requires a timeout.
1173 */
1174 if ((cp->val == 0x00 && timeout > 0) ||
1175 (cp->val == 0x02 && timeout == 0))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001176 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001177 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001178
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001179 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001180
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001181 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001182 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001183 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001184 goto failed;
1185 }
1186
1187 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001188 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001189 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001190 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001191 goto failed;
1192 }
1193
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001194 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001195 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001196 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001197 goto failed;
1198 }
1199
1200 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001201 bool changed = false;
1202
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001203 /* Setting limited discoverable when powered off is
1204 * not a valid operation since it requires a timeout
1205 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1206 */
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001207 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1208 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1209 changed = true;
1210 }
1211
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001212 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001213 if (err < 0)
1214 goto failed;
1215
1216 if (changed)
1217 err = new_settings(hdev, sk);
1218
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001219 goto failed;
1220 }
1221
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001222 /* If the current mode is the same, then just update the timeout
1223 * value with the new value. And if only the timeout gets updated,
1224 * then no need for any HCI transactions.
1225 */
1226 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) &&
1227 (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE,
1228 &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001229 cancel_delayed_work(&hdev->discov_off);
1230 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001231
Marcel Holtmann36261542013-10-15 08:28:51 -07001232 if (cp->val && hdev->discov_timeout > 0) {
1233 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001234 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001235 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001236 }
1237
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001238 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001239 goto failed;
1240 }
1241
1242 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1243 if (!cmd) {
1244 err = -ENOMEM;
1245 goto failed;
1246 }
1247
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001248 /* Cancel any potential discoverable timeout that might be
1249 * still active and store new timeout value. The arming of
1250 * the timeout happens in the complete handler.
1251 */
1252 cancel_delayed_work(&hdev->discov_off);
1253 hdev->discov_timeout = timeout;
1254
Johan Hedbergb456f872013-10-19 23:38:22 +03001255 /* Limited discoverable mode */
1256 if (cp->val == 0x02)
1257 set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1258 else
1259 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1260
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001261 hci_req_init(&req, hdev);
1262
Johan Hedberg9a43e252013-10-20 19:00:07 +03001263 /* The procedure for LE-only controllers is much simpler - just
1264 * update the advertising data.
1265 */
1266 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1267 goto update_ad;
1268
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001269 scan = SCAN_PAGE;
1270
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001271 if (cp->val) {
1272 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001273
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001274 if (cp->val == 0x02) {
1275 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001276 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001277 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1278 hci_cp.iac_lap[1] = 0x8b;
1279 hci_cp.iac_lap[2] = 0x9e;
1280 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1281 hci_cp.iac_lap[4] = 0x8b;
1282 hci_cp.iac_lap[5] = 0x9e;
1283 } else {
1284 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001285 hci_cp.num_iac = 1;
1286 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1287 hci_cp.iac_lap[1] = 0x8b;
1288 hci_cp.iac_lap[2] = 0x9e;
1289 }
1290
1291 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1292 (hci_cp.num_iac * 3) + 1, &hci_cp);
1293
1294 scan |= SCAN_INQUIRY;
1295 } else {
1296 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1297 }
1298
1299 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001300
Johan Hedberg9a43e252013-10-20 19:00:07 +03001301update_ad:
1302 update_adv_data(&req);
1303
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001304 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001305 if (err < 0)
1306 mgmt_pending_remove(cmd);
1307
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001308failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001309 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001310 return err;
1311}
1312
Johan Hedberg406d7802013-03-15 17:07:09 -05001313static void write_fast_connectable(struct hci_request *req, bool enable)
1314{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001315 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001316 struct hci_cp_write_page_scan_activity acp;
1317 u8 type;
1318
Johan Hedberg547003b2013-10-21 16:51:53 +03001319 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1320 return;
1321
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001322 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1323 return;
1324
Johan Hedberg406d7802013-03-15 17:07:09 -05001325 if (enable) {
1326 type = PAGE_SCAN_TYPE_INTERLACED;
1327
1328 /* 160 msec page scan interval */
1329 acp.interval = __constant_cpu_to_le16(0x0100);
1330 } else {
1331 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1332
1333 /* default 1.28 sec page scan */
1334 acp.interval = __constant_cpu_to_le16(0x0800);
1335 }
1336
1337 acp.window = __constant_cpu_to_le16(0x0012);
1338
Johan Hedbergbd98b992013-03-15 17:07:13 -05001339 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1340 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1341 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1342 sizeof(acp), &acp);
1343
1344 if (hdev->page_scan_type != type)
1345 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001346}
1347
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001348static u8 get_adv_type(struct hci_dev *hdev)
1349{
1350 struct pending_cmd *cmd;
1351 bool connectable;
1352
1353 /* If there's a pending mgmt command the flag will not yet have
1354 * it's final value, so check for this first.
1355 */
1356 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1357 if (cmd) {
1358 struct mgmt_mode *cp = cmd->param;
1359 connectable = !!cp->val;
1360 } else {
1361 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1362 }
1363
1364 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1365}
1366
Johan Hedberg95c66e72013-10-14 16:20:06 +03001367static void enable_advertising(struct hci_request *req)
1368{
1369 struct hci_dev *hdev = req->hdev;
1370 struct hci_cp_le_set_adv_param cp;
1371 u8 enable = 0x01;
1372
1373 memset(&cp, 0, sizeof(cp));
1374 cp.min_interval = __constant_cpu_to_le16(0x0800);
1375 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001376 cp.type = get_adv_type(hdev);
Marcel Holtmann79830f62013-10-18 16:38:09 -07001377 cp.own_address_type = hdev->own_addr_type;
Marcel Holtmann3f959d42014-02-20 11:55:56 -08001378 cp.channel_map = hdev->le_adv_channel_map;
Johan Hedberg95c66e72013-10-14 16:20:06 +03001379
1380 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1381
1382 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1383}
1384
1385static void disable_advertising(struct hci_request *req)
1386{
1387 u8 enable = 0x00;
1388
1389 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1390}
1391
Johan Hedberg2b76f452013-03-15 17:07:04 -05001392static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1393{
1394 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001395 struct mgmt_mode *cp;
1396 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001397
1398 BT_DBG("status 0x%02x", status);
1399
1400 hci_dev_lock(hdev);
1401
1402 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1403 if (!cmd)
1404 goto unlock;
1405
Johan Hedberg37438c12013-10-14 16:20:05 +03001406 if (status) {
1407 u8 mgmt_err = mgmt_status(status);
1408 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1409 goto remove_cmd;
1410 }
1411
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001412 cp = cmd->param;
1413 if (cp->val)
1414 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1415 else
1416 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1417
Johan Hedberg2b76f452013-03-15 17:07:04 -05001418 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1419
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001420 if (changed)
1421 new_settings(hdev, cmd->sk);
1422
Johan Hedberg37438c12013-10-14 16:20:05 +03001423remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001424 mgmt_pending_remove(cmd);
1425
1426unlock:
1427 hci_dev_unlock(hdev);
1428}
1429
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001430static int set_connectable_update_settings(struct hci_dev *hdev,
1431 struct sock *sk, u8 val)
1432{
1433 bool changed = false;
1434 int err;
1435
1436 if (!!val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1437 changed = true;
1438
1439 if (val) {
1440 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1441 } else {
1442 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1443 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1444 }
1445
1446 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1447 if (err < 0)
1448 return err;
1449
1450 if (changed)
1451 return new_settings(hdev, sk);
1452
1453 return 0;
1454}
1455
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001456static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001457 u16 len)
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001458{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001459 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001460 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001461 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001462 u8 scan;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001463 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001464
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001465 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001466
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001467 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1468 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001469 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001470 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001471
Johan Hedberga7e80f22013-01-09 16:05:19 +02001472 if (cp->val != 0x00 && cp->val != 0x01)
1473 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1474 MGMT_STATUS_INVALID_PARAMS);
1475
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001476 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001477
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001478 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001479 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001480 goto failed;
1481 }
1482
1483 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001484 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001485 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001486 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001487 goto failed;
1488 }
1489
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001490 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1491 if (!cmd) {
1492 err = -ENOMEM;
1493 goto failed;
1494 }
1495
Johan Hedberg2b76f452013-03-15 17:07:04 -05001496 hci_req_init(&req, hdev);
1497
Johan Hedberg9a43e252013-10-20 19:00:07 +03001498 /* If BR/EDR is not enabled and we disable advertising as a
1499 * by-product of disabling connectable, we need to update the
1500 * advertising flags.
1501 */
1502 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
1503 if (!cp->val) {
1504 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1505 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1506 }
1507 update_adv_data(&req);
1508 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001509 if (cp->val) {
1510 scan = SCAN_PAGE;
1511 } else {
1512 scan = 0;
1513
1514 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001515 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001516 cancel_delayed_work(&hdev->discov_off);
1517 }
1518
1519 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1520 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001521
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001522 /* If we're going from non-connectable to connectable or
1523 * vice-versa when fast connectable is enabled ensure that fast
1524 * connectable gets disabled. write_fast_connectable won't do
1525 * anything if the page scan parameters are already what they
1526 * should be.
1527 */
1528 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001529 write_fast_connectable(&req, false);
1530
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001531 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1532 hci_conn_num(hdev, LE_LINK) == 0) {
1533 disable_advertising(&req);
1534 enable_advertising(&req);
1535 }
1536
Johan Hedberg2b76f452013-03-15 17:07:04 -05001537 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001538 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001539 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001540 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03001541 err = set_connectable_update_settings(hdev, sk,
1542 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03001543 goto failed;
1544 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001545
1546failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001547 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001548 return err;
1549}
1550
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001551static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001552 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001553{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001554 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001555 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001556 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001557
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001558 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001559
Johan Hedberga7e80f22013-01-09 16:05:19 +02001560 if (cp->val != 0x00 && cp->val != 0x01)
1561 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1562 MGMT_STATUS_INVALID_PARAMS);
1563
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001564 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001565
1566 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001567 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001568 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001569 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001570
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001571 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001572 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001573 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001574
Marcel Holtmann55594352013-10-06 16:11:57 -07001575 if (changed)
1576 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001577
Marcel Holtmann55594352013-10-06 16:11:57 -07001578unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001579 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001580 return err;
1581}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001582
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001583static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1584 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001585{
1586 struct mgmt_mode *cp = data;
1587 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001588 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001589 int err;
1590
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001591 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001592
Johan Hedberge6fe7982013-10-02 15:45:22 +03001593 status = mgmt_bredr_support(hdev);
1594 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001595 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001596 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001597
Johan Hedberga7e80f22013-01-09 16:05:19 +02001598 if (cp->val != 0x00 && cp->val != 0x01)
1599 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1600 MGMT_STATUS_INVALID_PARAMS);
1601
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001602 hci_dev_lock(hdev);
1603
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001604 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001605 bool changed = false;
1606
1607 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001608 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001609 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1610 changed = true;
1611 }
1612
1613 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1614 if (err < 0)
1615 goto failed;
1616
1617 if (changed)
1618 err = new_settings(hdev, sk);
1619
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001620 goto failed;
1621 }
1622
1623 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001624 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001625 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001626 goto failed;
1627 }
1628
1629 val = !!cp->val;
1630
1631 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1632 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1633 goto failed;
1634 }
1635
1636 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1637 if (!cmd) {
1638 err = -ENOMEM;
1639 goto failed;
1640 }
1641
1642 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1643 if (err < 0) {
1644 mgmt_pending_remove(cmd);
1645 goto failed;
1646 }
1647
1648failed:
1649 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001650 return err;
1651}
1652
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001653static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001654{
1655 struct mgmt_mode *cp = data;
1656 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001657 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001658 int err;
1659
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001660 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001661
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001662 status = mgmt_bredr_support(hdev);
1663 if (status)
1664 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1665
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001666 if (!lmp_ssp_capable(hdev))
1667 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1668 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001669
Johan Hedberga7e80f22013-01-09 16:05:19 +02001670 if (cp->val != 0x00 && cp->val != 0x01)
1671 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1672 MGMT_STATUS_INVALID_PARAMS);
1673
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001674 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001675
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001676 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001677 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001678
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001679 if (cp->val) {
1680 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1681 &hdev->dev_flags);
1682 } else {
1683 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1684 &hdev->dev_flags);
1685 if (!changed)
1686 changed = test_and_clear_bit(HCI_HS_ENABLED,
1687 &hdev->dev_flags);
1688 else
1689 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001690 }
1691
1692 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1693 if (err < 0)
1694 goto failed;
1695
1696 if (changed)
1697 err = new_settings(hdev, sk);
1698
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001699 goto failed;
1700 }
1701
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001702 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1703 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001704 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1705 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001706 goto failed;
1707 }
1708
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001709 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001710 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1711 goto failed;
1712 }
1713
1714 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1715 if (!cmd) {
1716 err = -ENOMEM;
1717 goto failed;
1718 }
1719
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001720 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001721 if (err < 0) {
1722 mgmt_pending_remove(cmd);
1723 goto failed;
1724 }
1725
1726failed:
1727 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001728 return err;
1729}
1730
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001731static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001732{
1733 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001734 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001735 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001736 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001737
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001738 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001739
Johan Hedberge6fe7982013-10-02 15:45:22 +03001740 status = mgmt_bredr_support(hdev);
1741 if (status)
1742 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001743
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001744 if (!lmp_ssp_capable(hdev))
1745 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1746 MGMT_STATUS_NOT_SUPPORTED);
1747
1748 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1749 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1750 MGMT_STATUS_REJECTED);
1751
Johan Hedberga7e80f22013-01-09 16:05:19 +02001752 if (cp->val != 0x00 && cp->val != 0x01)
1753 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1754 MGMT_STATUS_INVALID_PARAMS);
1755
Marcel Holtmannee392692013-10-01 22:59:23 -07001756 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001757
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001758 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001759 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001760 } else {
1761 if (hdev_is_powered(hdev)) {
1762 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1763 MGMT_STATUS_REJECTED);
1764 goto unlock;
1765 }
1766
Marcel Holtmannee392692013-10-01 22:59:23 -07001767 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001768 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001769
1770 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1771 if (err < 0)
1772 goto unlock;
1773
1774 if (changed)
1775 err = new_settings(hdev, sk);
1776
1777unlock:
1778 hci_dev_unlock(hdev);
1779 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001780}
1781
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001782static void le_enable_complete(struct hci_dev *hdev, u8 status)
1783{
1784 struct cmd_lookup match = { NULL, hdev };
1785
1786 if (status) {
1787 u8 mgmt_err = mgmt_status(status);
1788
1789 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1790 &mgmt_err);
1791 return;
1792 }
1793
1794 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1795
1796 new_settings(hdev, match.sk);
1797
1798 if (match.sk)
1799 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001800
1801 /* Make sure the controller has a good default for
1802 * advertising data. Restrict the update to when LE
1803 * has actually been enabled. During power on, the
1804 * update in powered_update_hci will take care of it.
1805 */
1806 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1807 struct hci_request req;
1808
1809 hci_dev_lock(hdev);
1810
1811 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001812 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07001813 update_scan_rsp_data(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001814 hci_req_run(&req, NULL);
1815
1816 hci_dev_unlock(hdev);
1817 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001818}
1819
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001820static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001821{
1822 struct mgmt_mode *cp = data;
1823 struct hci_cp_write_le_host_supported hci_cp;
1824 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001825 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001826 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001827 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001828
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001829 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001830
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001831 if (!lmp_le_capable(hdev))
1832 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1833 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001834
Johan Hedberga7e80f22013-01-09 16:05:19 +02001835 if (cp->val != 0x00 && cp->val != 0x01)
1836 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1837 MGMT_STATUS_INVALID_PARAMS);
1838
Johan Hedbergc73eee92013-04-19 18:35:21 +03001839 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001840 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001841 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1842 MGMT_STATUS_REJECTED);
1843
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001844 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001845
1846 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001847 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001848
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001849 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001850 bool changed = false;
1851
1852 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1853 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1854 changed = true;
1855 }
1856
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001857 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1858 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001859 changed = true;
1860 }
1861
Johan Hedberg06199cf2012-02-22 16:37:11 +02001862 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1863 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001864 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001865
1866 if (changed)
1867 err = new_settings(hdev, sk);
1868
Johan Hedberg1de028c2012-02-29 19:55:35 -08001869 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001870 }
1871
Johan Hedberg4375f102013-09-25 13:26:10 +03001872 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1873 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001874 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001875 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001876 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001877 }
1878
1879 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1880 if (!cmd) {
1881 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001882 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001883 }
1884
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001885 hci_req_init(&req, hdev);
1886
Johan Hedberg06199cf2012-02-22 16:37:11 +02001887 memset(&hci_cp, 0, sizeof(hci_cp));
1888
1889 if (val) {
1890 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001891 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001892 } else {
1893 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1894 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001895 }
1896
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001897 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1898 &hci_cp);
1899
1900 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301901 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001902 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001903
Johan Hedberg1de028c2012-02-29 19:55:35 -08001904unlock:
1905 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001906 return err;
1907}
1908
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001909/* This is a helper function to test for pending mgmt commands that can
1910 * cause CoD or EIR HCI commands. We can only allow one such pending
1911 * mgmt command at a time since otherwise we cannot easily track what
1912 * the current values are, will be, and based on that calculate if a new
1913 * HCI command needs to be sent and if yes with what value.
1914 */
1915static bool pending_eir_or_class(struct hci_dev *hdev)
1916{
1917 struct pending_cmd *cmd;
1918
1919 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1920 switch (cmd->opcode) {
1921 case MGMT_OP_ADD_UUID:
1922 case MGMT_OP_REMOVE_UUID:
1923 case MGMT_OP_SET_DEV_CLASS:
1924 case MGMT_OP_SET_POWERED:
1925 return true;
1926 }
1927 }
1928
1929 return false;
1930}
1931
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001932static const u8 bluetooth_base_uuid[] = {
1933 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1934 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1935};
1936
1937static u8 get_uuid_size(const u8 *uuid)
1938{
1939 u32 val;
1940
1941 if (memcmp(uuid, bluetooth_base_uuid, 12))
1942 return 128;
1943
1944 val = get_unaligned_le32(&uuid[12]);
1945 if (val > 0xffff)
1946 return 32;
1947
1948 return 16;
1949}
1950
Johan Hedberg92da6092013-03-15 17:06:55 -05001951static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1952{
1953 struct pending_cmd *cmd;
1954
1955 hci_dev_lock(hdev);
1956
1957 cmd = mgmt_pending_find(mgmt_op, hdev);
1958 if (!cmd)
1959 goto unlock;
1960
1961 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1962 hdev->dev_class, 3);
1963
1964 mgmt_pending_remove(cmd);
1965
1966unlock:
1967 hci_dev_unlock(hdev);
1968}
1969
1970static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1971{
1972 BT_DBG("status 0x%02x", status);
1973
1974 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1975}
1976
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001977static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001978{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001979 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001980 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001981 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001982 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001983 int err;
1984
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001985 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001986
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001987 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001988
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001989 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001990 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001991 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001992 goto failed;
1993 }
1994
Andre Guedes92c4c202012-06-07 19:05:44 -03001995 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001996 if (!uuid) {
1997 err = -ENOMEM;
1998 goto failed;
1999 }
2000
2001 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002002 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002003 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002004
Johan Hedbergde66aa62013-01-27 00:31:27 +02002005 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002006
Johan Hedberg890ea892013-03-15 17:06:52 -05002007 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002008
Johan Hedberg890ea892013-03-15 17:06:52 -05002009 update_class(&req);
2010 update_eir(&req);
2011
Johan Hedberg92da6092013-03-15 17:06:55 -05002012 err = hci_req_run(&req, add_uuid_complete);
2013 if (err < 0) {
2014 if (err != -ENODATA)
2015 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002016
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002017 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002018 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002019 goto failed;
2020 }
2021
2022 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002023 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002024 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002025 goto failed;
2026 }
2027
2028 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002029
2030failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002031 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002032 return err;
2033}
2034
Johan Hedberg24b78d02012-02-23 23:24:30 +02002035static bool enable_service_cache(struct hci_dev *hdev)
2036{
2037 if (!hdev_is_powered(hdev))
2038 return false;
2039
2040 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002041 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2042 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002043 return true;
2044 }
2045
2046 return false;
2047}
2048
Johan Hedberg92da6092013-03-15 17:06:55 -05002049static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
2050{
2051 BT_DBG("status 0x%02x", status);
2052
2053 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2054}
2055
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002056static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002057 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002058{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002059 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002060 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002061 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002062 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 -05002063 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002064 int err, found;
2065
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002066 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002067
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002068 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002069
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002070 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002071 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002072 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002073 goto unlock;
2074 }
2075
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002076 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002077 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002078
Johan Hedberg24b78d02012-02-23 23:24:30 +02002079 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002080 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002081 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002082 goto unlock;
2083 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002084
Johan Hedberg9246a862012-02-23 21:33:16 +02002085 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002086 }
2087
2088 found = 0;
2089
Johan Hedberg056341c2013-01-27 00:31:30 +02002090 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002091 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2092 continue;
2093
2094 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002095 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002096 found++;
2097 }
2098
2099 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002100 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002101 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002102 goto unlock;
2103 }
2104
Johan Hedberg9246a862012-02-23 21:33:16 +02002105update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002106 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002107
Johan Hedberg890ea892013-03-15 17:06:52 -05002108 update_class(&req);
2109 update_eir(&req);
2110
Johan Hedberg92da6092013-03-15 17:06:55 -05002111 err = hci_req_run(&req, remove_uuid_complete);
2112 if (err < 0) {
2113 if (err != -ENODATA)
2114 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002115
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002116 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002117 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002118 goto unlock;
2119 }
2120
2121 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002122 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002123 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002124 goto unlock;
2125 }
2126
2127 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002128
2129unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002130 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002131 return err;
2132}
2133
Johan Hedberg92da6092013-03-15 17:06:55 -05002134static void set_class_complete(struct hci_dev *hdev, u8 status)
2135{
2136 BT_DBG("status 0x%02x", status);
2137
2138 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2139}
2140
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002141static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002142 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002143{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002144 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002145 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002146 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002147 int err;
2148
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002149 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002150
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002151 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002152 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2153 MGMT_STATUS_NOT_SUPPORTED);
2154
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002155 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002156
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002157 if (pending_eir_or_class(hdev)) {
2158 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2159 MGMT_STATUS_BUSY);
2160 goto unlock;
2161 }
2162
2163 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2164 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2165 MGMT_STATUS_INVALID_PARAMS);
2166 goto unlock;
2167 }
2168
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002169 hdev->major_class = cp->major;
2170 hdev->minor_class = cp->minor;
2171
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002172 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002173 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002174 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002175 goto unlock;
2176 }
2177
Johan Hedberg890ea892013-03-15 17:06:52 -05002178 hci_req_init(&req, hdev);
2179
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002180 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002181 hci_dev_unlock(hdev);
2182 cancel_delayed_work_sync(&hdev->service_cache);
2183 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002184 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002185 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002186
Johan Hedberg890ea892013-03-15 17:06:52 -05002187 update_class(&req);
2188
Johan Hedberg92da6092013-03-15 17:06:55 -05002189 err = hci_req_run(&req, set_class_complete);
2190 if (err < 0) {
2191 if (err != -ENODATA)
2192 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002193
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002194 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002195 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002196 goto unlock;
2197 }
2198
2199 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002200 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002201 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002202 goto unlock;
2203 }
2204
2205 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002206
Johan Hedbergb5235a62012-02-21 14:32:24 +02002207unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002208 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002209 return err;
2210}
2211
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002212static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002213 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002214{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002215 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002216 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002217 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002218 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002219
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002220 BT_DBG("request for %s", hdev->name);
2221
2222 if (!lmp_bredr_capable(hdev))
2223 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2224 MGMT_STATUS_NOT_SUPPORTED);
2225
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002226 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002227
Johan Hedberg86742e12011-11-07 23:13:38 +02002228 expected_len = sizeof(*cp) + key_count *
2229 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002230 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002231 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002232 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002233 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002234 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002235 }
2236
Johan Hedberg4ae143012013-01-20 14:27:13 +02002237 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2238 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2239 MGMT_STATUS_INVALID_PARAMS);
2240
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002241 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002242 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002243
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002244 for (i = 0; i < key_count; i++) {
2245 struct mgmt_link_key_info *key = &cp->keys[i];
2246
Marcel Holtmann8e991132014-01-10 02:07:25 -08002247 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002248 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2249 MGMT_STATUS_INVALID_PARAMS);
2250 }
2251
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002252 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002253
2254 hci_link_keys_clear(hdev);
2255
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002256 if (cp->debug_keys)
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002257 changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002258 else
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002259 changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
2260
2261 if (changed)
2262 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002263
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002264 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002265 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002266
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002267 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002268 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002269 }
2270
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002271 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002272
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002273 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002274
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002275 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002276}
2277
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002278static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002279 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002280{
2281 struct mgmt_ev_device_unpaired ev;
2282
2283 bacpy(&ev.addr.bdaddr, bdaddr);
2284 ev.addr.type = addr_type;
2285
2286 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002287 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002288}
2289
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002290static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002291 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002292{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002293 struct mgmt_cp_unpair_device *cp = data;
2294 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002295 struct hci_cp_disconnect dc;
2296 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002297 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002298 int err;
2299
Johan Hedberga8a1d192011-11-10 15:54:38 +02002300 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002301 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2302 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002303
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002304 if (!bdaddr_type_is_valid(cp->addr.type))
2305 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2306 MGMT_STATUS_INVALID_PARAMS,
2307 &rp, sizeof(rp));
2308
Johan Hedberg118da702013-01-20 14:27:20 +02002309 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2310 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2311 MGMT_STATUS_INVALID_PARAMS,
2312 &rp, sizeof(rp));
2313
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002314 hci_dev_lock(hdev);
2315
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002316 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002317 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002318 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002319 goto unlock;
2320 }
2321
Johan Hedberge0b2b272014-02-18 17:14:31 +02002322 if (cp->addr.type == BDADDR_BREDR) {
Johan Hedberg124f6e32012-02-09 13:50:12 +02002323 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedberge0b2b272014-02-18 17:14:31 +02002324 } else {
2325 u8 addr_type;
2326
2327 if (cp->addr.type == BDADDR_LE_PUBLIC)
2328 addr_type = ADDR_LE_DEV_PUBLIC;
2329 else
2330 addr_type = ADDR_LE_DEV_RANDOM;
2331
Johan Hedberga7ec7332014-02-18 17:14:35 +02002332 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2333
Johan Hedberge0b2b272014-02-18 17:14:31 +02002334 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
2335 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002336
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002337 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002338 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002339 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002340 goto unlock;
2341 }
2342
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002343 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002344 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002345 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002346 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002347 else
2348 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002349 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002350 } else {
2351 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002352 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002353
Johan Hedberga8a1d192011-11-10 15:54:38 +02002354 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002355 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002356 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002357 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002358 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002359 }
2360
Johan Hedberg124f6e32012-02-09 13:50:12 +02002361 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002362 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002363 if (!cmd) {
2364 err = -ENOMEM;
2365 goto unlock;
2366 }
2367
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002368 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002369 dc.reason = 0x13; /* Remote User Terminated Connection */
2370 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2371 if (err < 0)
2372 mgmt_pending_remove(cmd);
2373
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002374unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002375 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002376 return err;
2377}
2378
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002379static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002380 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002381{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002382 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002383 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002384 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002385 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002386 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002387 int err;
2388
2389 BT_DBG("");
2390
Johan Hedberg06a63b12013-01-20 14:27:21 +02002391 memset(&rp, 0, sizeof(rp));
2392 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2393 rp.addr.type = cp->addr.type;
2394
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002395 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002396 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2397 MGMT_STATUS_INVALID_PARAMS,
2398 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002399
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002400 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002401
2402 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002403 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2404 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002405 goto failed;
2406 }
2407
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002408 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002409 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2410 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002411 goto failed;
2412 }
2413
Andre Guedes591f47f2012-04-24 21:02:49 -03002414 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002415 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2416 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002417 else
2418 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002419
Vishal Agarwalf9607272012-06-13 05:32:43 +05302420 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002421 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2422 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002423 goto failed;
2424 }
2425
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002426 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002427 if (!cmd) {
2428 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002429 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002430 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002431
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002432 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002433 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002434
2435 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2436 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002437 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002438
2439failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002440 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002441 return err;
2442}
2443
Andre Guedes57c14772012-04-24 21:02:50 -03002444static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002445{
2446 switch (link_type) {
2447 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002448 switch (addr_type) {
2449 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002450 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002451
Johan Hedberg48264f02011-11-09 13:58:58 +02002452 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002453 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002454 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002455 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002456
Johan Hedberg4c659c32011-11-07 23:13:39 +02002457 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002458 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002459 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002460 }
2461}
2462
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002463static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2464 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002465{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002466 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002467 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002468 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002469 int err;
2470 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002471
2472 BT_DBG("");
2473
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002474 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002475
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002476 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002477 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002478 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002479 goto unlock;
2480 }
2481
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002482 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002483 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2484 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002485 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002486 }
2487
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002488 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002489 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002490 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002491 err = -ENOMEM;
2492 goto unlock;
2493 }
2494
Johan Hedberg2784eb42011-01-21 13:56:35 +02002495 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002496 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002497 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2498 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002499 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002500 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002501 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002502 continue;
2503 i++;
2504 }
2505
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002506 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002507
Johan Hedberg4c659c32011-11-07 23:13:39 +02002508 /* Recalculate length in case of filtered SCO connections, etc */
2509 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002510
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002511 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002512 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002513
Johan Hedberga38528f2011-01-22 06:46:43 +02002514 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002515
2516unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002517 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002518 return err;
2519}
2520
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002521static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002522 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002523{
2524 struct pending_cmd *cmd;
2525 int err;
2526
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002527 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002528 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002529 if (!cmd)
2530 return -ENOMEM;
2531
Johan Hedbergd8457692012-02-17 14:24:57 +02002532 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002533 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002534 if (err < 0)
2535 mgmt_pending_remove(cmd);
2536
2537 return err;
2538}
2539
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002540static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002541 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002542{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002543 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002544 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002545 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002546 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002547 int err;
2548
2549 BT_DBG("");
2550
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002551 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002552
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002553 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002554 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002555 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002556 goto failed;
2557 }
2558
Johan Hedbergd8457692012-02-17 14:24:57 +02002559 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002560 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002561 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002562 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002563 goto failed;
2564 }
2565
2566 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002567 struct mgmt_cp_pin_code_neg_reply ncp;
2568
2569 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002570
2571 BT_ERR("PIN code is not 16 bytes long");
2572
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002573 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002574 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002575 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002576 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002577
2578 goto failed;
2579 }
2580
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002581 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002582 if (!cmd) {
2583 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002584 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002585 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002586
Johan Hedbergd8457692012-02-17 14:24:57 +02002587 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002588 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002589 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002590
2591 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2592 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002593 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002594
2595failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002596 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002597 return err;
2598}
2599
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002600static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2601 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002602{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002603 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002604
2605 BT_DBG("");
2606
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002607 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002608
2609 hdev->io_capability = cp->io_capability;
2610
2611 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002612 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002613
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002614 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002615
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002616 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2617 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002618}
2619
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002620static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002621{
2622 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002623 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002624
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002625 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002626 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2627 continue;
2628
Johan Hedberge9a416b2011-02-19 12:05:56 -03002629 if (cmd->user_data != conn)
2630 continue;
2631
2632 return cmd;
2633 }
2634
2635 return NULL;
2636}
2637
2638static void pairing_complete(struct pending_cmd *cmd, u8 status)
2639{
2640 struct mgmt_rp_pair_device rp;
2641 struct hci_conn *conn = cmd->user_data;
2642
Johan Hedbergba4e5642011-11-11 00:07:34 +02002643 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002644 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002645
Johan Hedbergaee9b212012-02-18 15:07:59 +02002646 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002647 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002648
2649 /* So we don't get further callbacks for this connection */
2650 conn->connect_cfm_cb = NULL;
2651 conn->security_cfm_cb = NULL;
2652 conn->disconn_cfm_cb = NULL;
2653
David Herrmann76a68ba2013-04-06 20:28:37 +02002654 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002655
Johan Hedberga664b5b2011-02-19 12:06:02 -03002656 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002657}
2658
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002659void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2660{
2661 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
2662 struct pending_cmd *cmd;
2663
2664 cmd = find_pairing(conn);
2665 if (cmd)
2666 pairing_complete(cmd, status);
2667}
2668
Johan Hedberge9a416b2011-02-19 12:05:56 -03002669static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2670{
2671 struct pending_cmd *cmd;
2672
2673 BT_DBG("status %u", status);
2674
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002675 cmd = find_pairing(conn);
2676 if (!cmd)
2677 BT_DBG("Unable to find a pending command");
2678 else
Johan Hedberge2113262012-02-18 15:20:03 +02002679 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002680}
2681
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002682static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302683{
2684 struct pending_cmd *cmd;
2685
2686 BT_DBG("status %u", status);
2687
2688 if (!status)
2689 return;
2690
2691 cmd = find_pairing(conn);
2692 if (!cmd)
2693 BT_DBG("Unable to find a pending command");
2694 else
2695 pairing_complete(cmd, mgmt_status(status));
2696}
2697
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002698static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002699 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002700{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002701 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002702 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002703 struct pending_cmd *cmd;
2704 u8 sec_level, auth_type;
2705 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002706 int err;
2707
2708 BT_DBG("");
2709
Szymon Jancf950a30e2013-01-18 12:48:07 +01002710 memset(&rp, 0, sizeof(rp));
2711 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2712 rp.addr.type = cp->addr.type;
2713
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002714 if (!bdaddr_type_is_valid(cp->addr.type))
2715 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2716 MGMT_STATUS_INVALID_PARAMS,
2717 &rp, sizeof(rp));
2718
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002719 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002720
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002721 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002722 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2723 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002724 goto unlock;
2725 }
2726
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002727 sec_level = BT_SECURITY_MEDIUM;
2728 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002729 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002730 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002731 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002732
Andre Guedes591f47f2012-04-24 21:02:49 -03002733 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002734 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2735 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002736 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002737 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2738 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002739
Ville Tervo30e76272011-02-22 16:10:53 -03002740 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002741 int status;
2742
2743 if (PTR_ERR(conn) == -EBUSY)
2744 status = MGMT_STATUS_BUSY;
2745 else
2746 status = MGMT_STATUS_CONNECT_FAILED;
2747
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002748 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002749 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002750 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002751 goto unlock;
2752 }
2753
2754 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002755 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002756 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002757 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002758 goto unlock;
2759 }
2760
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002761 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002762 if (!cmd) {
2763 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002764 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002765 goto unlock;
2766 }
2767
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002768 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002769 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002770 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002771 conn->security_cfm_cb = pairing_complete_cb;
2772 conn->disconn_cfm_cb = pairing_complete_cb;
2773 } else {
2774 conn->connect_cfm_cb = le_pairing_complete_cb;
2775 conn->security_cfm_cb = le_pairing_complete_cb;
2776 conn->disconn_cfm_cb = le_pairing_complete_cb;
2777 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002778
Johan Hedberge9a416b2011-02-19 12:05:56 -03002779 conn->io_capability = cp->io_cap;
2780 cmd->user_data = conn;
2781
2782 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002783 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002784 pairing_complete(cmd, 0);
2785
2786 err = 0;
2787
2788unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002789 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002790 return err;
2791}
2792
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002793static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2794 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002795{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002796 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002797 struct pending_cmd *cmd;
2798 struct hci_conn *conn;
2799 int err;
2800
2801 BT_DBG("");
2802
Johan Hedberg28424702012-02-02 04:02:29 +02002803 hci_dev_lock(hdev);
2804
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002805 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002806 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002807 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002808 goto unlock;
2809 }
2810
Johan Hedberg28424702012-02-02 04:02:29 +02002811 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2812 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002813 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002814 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002815 goto unlock;
2816 }
2817
2818 conn = cmd->user_data;
2819
2820 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002821 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002822 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002823 goto unlock;
2824 }
2825
2826 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2827
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002828 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002829 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002830unlock:
2831 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002832 return err;
2833}
2834
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002835static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002836 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002837 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002838{
Johan Hedberga5c29682011-02-19 12:05:57 -03002839 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002840 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002841 int err;
2842
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002843 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002844
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002845 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002846 err = cmd_complete(sk, hdev->id, mgmt_op,
2847 MGMT_STATUS_NOT_POWERED, addr,
2848 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002849 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002850 }
2851
Johan Hedberg1707c602013-03-15 17:07:15 -05002852 if (addr->type == BDADDR_BREDR)
2853 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002854 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002855 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002856
Johan Hedberg272d90d2012-02-09 15:26:12 +02002857 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002858 err = cmd_complete(sk, hdev->id, mgmt_op,
2859 MGMT_STATUS_NOT_CONNECTED, addr,
2860 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002861 goto done;
2862 }
2863
Johan Hedberg1707c602013-03-15 17:07:15 -05002864 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002865 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002866 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002867
Brian Gix5fe57d92011-12-21 16:12:13 -08002868 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002869 err = cmd_complete(sk, hdev->id, mgmt_op,
2870 MGMT_STATUS_SUCCESS, addr,
2871 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002872 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002873 err = cmd_complete(sk, hdev->id, mgmt_op,
2874 MGMT_STATUS_FAILED, addr,
2875 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002876
Brian Gix47c15e22011-11-16 13:53:14 -08002877 goto done;
2878 }
2879
Johan Hedberg1707c602013-03-15 17:07:15 -05002880 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002881 if (!cmd) {
2882 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002883 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002884 }
2885
Brian Gix0df4c182011-11-16 13:53:13 -08002886 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002887 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2888 struct hci_cp_user_passkey_reply cp;
2889
Johan Hedberg1707c602013-03-15 17:07:15 -05002890 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002891 cp.passkey = passkey;
2892 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2893 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002894 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2895 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002896
Johan Hedberga664b5b2011-02-19 12:06:02 -03002897 if (err < 0)
2898 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002899
Brian Gix0df4c182011-11-16 13:53:13 -08002900done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002901 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002902 return err;
2903}
2904
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302905static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2906 void *data, u16 len)
2907{
2908 struct mgmt_cp_pin_code_neg_reply *cp = data;
2909
2910 BT_DBG("");
2911
Johan Hedberg1707c602013-03-15 17:07:15 -05002912 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302913 MGMT_OP_PIN_CODE_NEG_REPLY,
2914 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2915}
2916
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002917static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2918 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002919{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002920 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002921
2922 BT_DBG("");
2923
2924 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002925 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002926 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002927
Johan Hedberg1707c602013-03-15 17:07:15 -05002928 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002929 MGMT_OP_USER_CONFIRM_REPLY,
2930 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002931}
2932
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002933static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002934 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002935{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002936 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002937
2938 BT_DBG("");
2939
Johan Hedberg1707c602013-03-15 17:07:15 -05002940 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002941 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2942 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002943}
2944
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002945static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2946 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002947{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002948 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002949
2950 BT_DBG("");
2951
Johan Hedberg1707c602013-03-15 17:07:15 -05002952 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002953 MGMT_OP_USER_PASSKEY_REPLY,
2954 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002955}
2956
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002957static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002958 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002959{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002960 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002961
2962 BT_DBG("");
2963
Johan Hedberg1707c602013-03-15 17:07:15 -05002964 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002965 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2966 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002967}
2968
Johan Hedberg13928972013-03-15 17:07:00 -05002969static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002970{
Johan Hedberg13928972013-03-15 17:07:00 -05002971 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002972 struct hci_cp_write_local_name cp;
2973
Johan Hedberg13928972013-03-15 17:07:00 -05002974 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002975
Johan Hedberg890ea892013-03-15 17:06:52 -05002976 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002977}
2978
Johan Hedberg13928972013-03-15 17:07:00 -05002979static void set_name_complete(struct hci_dev *hdev, u8 status)
2980{
2981 struct mgmt_cp_set_local_name *cp;
2982 struct pending_cmd *cmd;
2983
2984 BT_DBG("status 0x%02x", status);
2985
2986 hci_dev_lock(hdev);
2987
2988 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2989 if (!cmd)
2990 goto unlock;
2991
2992 cp = cmd->param;
2993
2994 if (status)
2995 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2996 mgmt_status(status));
2997 else
2998 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2999 cp, sizeof(*cp));
3000
3001 mgmt_pending_remove(cmd);
3002
3003unlock:
3004 hci_dev_unlock(hdev);
3005}
3006
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003007static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003008 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003009{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003010 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003011 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003012 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003013 int err;
3014
3015 BT_DBG("");
3016
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003017 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003018
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003019 /* If the old values are the same as the new ones just return a
3020 * direct command complete event.
3021 */
3022 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3023 !memcmp(hdev->short_name, cp->short_name,
3024 sizeof(hdev->short_name))) {
3025 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3026 data, len);
3027 goto failed;
3028 }
3029
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003030 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003031
Johan Hedbergb5235a62012-02-21 14:32:24 +02003032 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003033 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003034
3035 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003036 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003037 if (err < 0)
3038 goto failed;
3039
3040 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003041 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003042
Johan Hedbergb5235a62012-02-21 14:32:24 +02003043 goto failed;
3044 }
3045
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003046 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003047 if (!cmd) {
3048 err = -ENOMEM;
3049 goto failed;
3050 }
3051
Johan Hedberg13928972013-03-15 17:07:00 -05003052 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3053
Johan Hedberg890ea892013-03-15 17:06:52 -05003054 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003055
3056 if (lmp_bredr_capable(hdev)) {
3057 update_name(&req);
3058 update_eir(&req);
3059 }
3060
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003061 /* The name is stored in the scan response data and so
3062 * no need to udpate the advertising data here.
3063 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003064 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003065 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003066
Johan Hedberg13928972013-03-15 17:07:00 -05003067 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003068 if (err < 0)
3069 mgmt_pending_remove(cmd);
3070
3071failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003072 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003073 return err;
3074}
3075
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003076static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003077 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003078{
Szymon Jancc35938b2011-03-22 13:12:21 +01003079 struct pending_cmd *cmd;
3080 int err;
3081
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003082 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003083
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003084 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003085
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003086 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003087 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003088 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003089 goto unlock;
3090 }
3091
Andre Guedes9a1a1992012-07-24 15:03:48 -03003092 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003093 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003094 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003095 goto unlock;
3096 }
3097
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003098 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003099 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003100 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003101 goto unlock;
3102 }
3103
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003104 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003105 if (!cmd) {
3106 err = -ENOMEM;
3107 goto unlock;
3108 }
3109
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003110 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
3111 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
3112 0, NULL);
3113 else
3114 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3115
Szymon Jancc35938b2011-03-22 13:12:21 +01003116 if (err < 0)
3117 mgmt_pending_remove(cmd);
3118
3119unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003120 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003121 return err;
3122}
3123
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003124static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003125 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003126{
Szymon Janc2763eda2011-03-22 13:12:22 +01003127 int err;
3128
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003129 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003130
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003131 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003132
Marcel Holtmannec109112014-01-10 02:07:30 -08003133 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3134 struct mgmt_cp_add_remote_oob_data *cp = data;
3135 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003136
Marcel Holtmannec109112014-01-10 02:07:30 -08003137 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
3138 cp->hash, cp->randomizer);
3139 if (err < 0)
3140 status = MGMT_STATUS_FAILED;
3141 else
3142 status = MGMT_STATUS_SUCCESS;
3143
3144 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3145 status, &cp->addr, sizeof(cp->addr));
3146 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3147 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
3148 u8 status;
3149
3150 err = hci_add_remote_oob_ext_data(hdev, &cp->addr.bdaddr,
3151 cp->hash192,
3152 cp->randomizer192,
3153 cp->hash256,
3154 cp->randomizer256);
3155 if (err < 0)
3156 status = MGMT_STATUS_FAILED;
3157 else
3158 status = MGMT_STATUS_SUCCESS;
3159
3160 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3161 status, &cp->addr, sizeof(cp->addr));
3162 } else {
3163 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
3164 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3165 MGMT_STATUS_INVALID_PARAMS);
3166 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003167
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003168 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003169 return err;
3170}
3171
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003172static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003173 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003174{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003175 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003176 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003177 int err;
3178
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003179 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003180
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003181 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003182
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003183 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003184 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003185 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003186 else
Szymon Janca6785be2012-12-13 15:11:21 +01003187 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003188
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003189 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003190 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003191
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003192 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003193 return err;
3194}
3195
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003196static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3197{
3198 struct pending_cmd *cmd;
3199 u8 type;
3200 int err;
3201
3202 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3203
3204 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3205 if (!cmd)
3206 return -ENOENT;
3207
3208 type = hdev->discovery.type;
3209
3210 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3211 &type, sizeof(type));
3212 mgmt_pending_remove(cmd);
3213
3214 return err;
3215}
3216
Andre Guedes7c307722013-04-30 15:29:28 -03003217static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3218{
3219 BT_DBG("status %d", status);
3220
3221 if (status) {
3222 hci_dev_lock(hdev);
3223 mgmt_start_discovery_failed(hdev, status);
3224 hci_dev_unlock(hdev);
3225 return;
3226 }
3227
3228 hci_dev_lock(hdev);
3229 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3230 hci_dev_unlock(hdev);
3231
3232 switch (hdev->discovery.type) {
3233 case DISCOV_TYPE_LE:
3234 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003235 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003236 break;
3237
3238 case DISCOV_TYPE_INTERLEAVED:
3239 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003240 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003241 break;
3242
3243 case DISCOV_TYPE_BREDR:
3244 break;
3245
3246 default:
3247 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3248 }
3249}
3250
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003251static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003252 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003253{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003254 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003255 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003256 struct hci_cp_le_set_scan_param param_cp;
3257 struct hci_cp_le_set_scan_enable enable_cp;
3258 struct hci_cp_inquiry inq_cp;
3259 struct hci_request req;
3260 /* General inquiry access code (GIAC) */
3261 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003262 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003263 int err;
3264
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003265 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003266
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003267 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003268
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003269 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003270 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003271 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003272 goto failed;
3273 }
3274
Andre Guedes642be6c2012-03-21 00:03:37 -03003275 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3276 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3277 MGMT_STATUS_BUSY);
3278 goto failed;
3279 }
3280
Johan Hedbergff9ef572012-01-04 14:23:45 +02003281 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003282 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003283 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003284 goto failed;
3285 }
3286
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003287 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003288 if (!cmd) {
3289 err = -ENOMEM;
3290 goto failed;
3291 }
3292
Andre Guedes4aab14e2012-02-17 20:39:36 -03003293 hdev->discovery.type = cp->type;
3294
Andre Guedes7c307722013-04-30 15:29:28 -03003295 hci_req_init(&req, hdev);
3296
Andre Guedes4aab14e2012-02-17 20:39:36 -03003297 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003298 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003299 status = mgmt_bredr_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 (test_bit(HCI_INQUIRY, &hdev->flags)) {
3308 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3309 MGMT_STATUS_BUSY);
3310 mgmt_pending_remove(cmd);
3311 goto failed;
3312 }
3313
3314 hci_inquiry_cache_flush(hdev);
3315
3316 memset(&inq_cp, 0, sizeof(inq_cp));
3317 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003318 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003319 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003320 break;
3321
3322 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003323 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003324 status = mgmt_le_support(hdev);
3325 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003326 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003327 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003328 mgmt_pending_remove(cmd);
3329 goto failed;
3330 }
3331
Andre Guedes7c307722013-04-30 15:29:28 -03003332 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003333 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003334 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3335 MGMT_STATUS_NOT_SUPPORTED);
3336 mgmt_pending_remove(cmd);
3337 goto failed;
3338 }
3339
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003340 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003341 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3342 MGMT_STATUS_REJECTED);
3343 mgmt_pending_remove(cmd);
3344 goto failed;
3345 }
3346
3347 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3348 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3349 MGMT_STATUS_BUSY);
3350 mgmt_pending_remove(cmd);
3351 goto failed;
3352 }
3353
3354 memset(&param_cp, 0, sizeof(param_cp));
3355 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003356 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3357 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmann79830f62013-10-18 16:38:09 -07003358 param_cp.own_address_type = hdev->own_addr_type;
Andre Guedes7c307722013-04-30 15:29:28 -03003359 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3360 &param_cp);
3361
3362 memset(&enable_cp, 0, sizeof(enable_cp));
3363 enable_cp.enable = LE_SCAN_ENABLE;
3364 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3365 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3366 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003367 break;
3368
Andre Guedesf39799f2012-02-17 20:39:35 -03003369 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003370 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3371 MGMT_STATUS_INVALID_PARAMS);
3372 mgmt_pending_remove(cmd);
3373 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003374 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003375
Andre Guedes7c307722013-04-30 15:29:28 -03003376 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003377 if (err < 0)
3378 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003379 else
3380 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003381
3382failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003383 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003384 return err;
3385}
3386
Andre Guedes1183fdc2013-04-30 15:29:35 -03003387static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3388{
3389 struct pending_cmd *cmd;
3390 int err;
3391
3392 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3393 if (!cmd)
3394 return -ENOENT;
3395
3396 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3397 &hdev->discovery.type, sizeof(hdev->discovery.type));
3398 mgmt_pending_remove(cmd);
3399
3400 return err;
3401}
3402
Andre Guedes0e05bba2013-04-30 15:29:33 -03003403static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3404{
3405 BT_DBG("status %d", status);
3406
3407 hci_dev_lock(hdev);
3408
3409 if (status) {
3410 mgmt_stop_discovery_failed(hdev, status);
3411 goto unlock;
3412 }
3413
3414 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3415
3416unlock:
3417 hci_dev_unlock(hdev);
3418}
3419
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003420static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003421 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003422{
Johan Hedbergd9306502012-02-20 23:25:18 +02003423 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003424 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003425 struct hci_cp_remote_name_req_cancel cp;
3426 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003427 struct hci_request req;
3428 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003429 int err;
3430
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003431 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003432
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003433 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003434
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003435 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003436 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003437 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3438 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003439 goto unlock;
3440 }
3441
3442 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003443 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003444 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3445 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003446 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003447 }
3448
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003449 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003450 if (!cmd) {
3451 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003452 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003453 }
3454
Andre Guedes0e05bba2013-04-30 15:29:33 -03003455 hci_req_init(&req, hdev);
3456
Andre Guedese0d9727e2012-03-20 15:15:36 -03003457 switch (hdev->discovery.state) {
3458 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003459 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3460 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3461 } else {
3462 cancel_delayed_work(&hdev->le_scan_disable);
3463
3464 memset(&enable_cp, 0, sizeof(enable_cp));
3465 enable_cp.enable = LE_SCAN_DISABLE;
3466 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3467 sizeof(enable_cp), &enable_cp);
3468 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003469
Andre Guedese0d9727e2012-03-20 15:15:36 -03003470 break;
3471
3472 case DISCOVERY_RESOLVING:
3473 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003474 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003475 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003476 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003477 err = cmd_complete(sk, hdev->id,
3478 MGMT_OP_STOP_DISCOVERY, 0,
3479 &mgmt_cp->type,
3480 sizeof(mgmt_cp->type));
3481 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3482 goto unlock;
3483 }
3484
3485 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003486 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3487 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003488
3489 break;
3490
3491 default:
3492 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003493
3494 mgmt_pending_remove(cmd);
3495 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3496 MGMT_STATUS_FAILED, &mgmt_cp->type,
3497 sizeof(mgmt_cp->type));
3498 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003499 }
3500
Andre Guedes0e05bba2013-04-30 15:29:33 -03003501 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003502 if (err < 0)
3503 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003504 else
3505 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003506
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003507unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003508 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003509 return err;
3510}
3511
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003512static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003513 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003514{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003515 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003516 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003517 int err;
3518
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003519 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003520
Johan Hedberg561aafb2012-01-04 13:31:59 +02003521 hci_dev_lock(hdev);
3522
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003523 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003524 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003525 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003526 goto failed;
3527 }
3528
Johan Hedberga198e7b2012-02-17 14:27:06 +02003529 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003530 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003531 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003532 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003533 goto failed;
3534 }
3535
3536 if (cp->name_known) {
3537 e->name_state = NAME_KNOWN;
3538 list_del(&e->list);
3539 } else {
3540 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02003541 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003542 }
3543
Johan Hedberge3846622013-01-09 15:29:33 +02003544 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3545 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003546
3547failed:
3548 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003549 return err;
3550}
3551
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003552static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003553 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003554{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003555 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003556 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003557 int err;
3558
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003559 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003560
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003561 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003562 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3563 MGMT_STATUS_INVALID_PARAMS,
3564 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003565
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003566 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003567
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003568 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003569 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003570 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003571 else
Szymon Janca6785be2012-12-13 15:11:21 +01003572 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003573
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003574 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003575 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003576
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003577 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003578
3579 return err;
3580}
3581
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003582static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003583 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003584{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003585 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003586 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003587 int err;
3588
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003589 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003590
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003591 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003592 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3593 MGMT_STATUS_INVALID_PARAMS,
3594 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003595
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003596 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003597
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003598 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003599 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003600 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003601 else
Szymon Janca6785be2012-12-13 15:11:21 +01003602 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003603
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003604 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003605 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003606
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003607 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003608
3609 return err;
3610}
3611
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003612static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3613 u16 len)
3614{
3615 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003616 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003617 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003618 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003619
3620 BT_DBG("%s", hdev->name);
3621
Szymon Jancc72d4b82012-03-16 16:02:57 +01003622 source = __le16_to_cpu(cp->source);
3623
3624 if (source > 0x0002)
3625 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3626 MGMT_STATUS_INVALID_PARAMS);
3627
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003628 hci_dev_lock(hdev);
3629
Szymon Jancc72d4b82012-03-16 16:02:57 +01003630 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003631 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3632 hdev->devid_product = __le16_to_cpu(cp->product);
3633 hdev->devid_version = __le16_to_cpu(cp->version);
3634
3635 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3636
Johan Hedberg890ea892013-03-15 17:06:52 -05003637 hci_req_init(&req, hdev);
3638 update_eir(&req);
3639 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003640
3641 hci_dev_unlock(hdev);
3642
3643 return err;
3644}
3645
Johan Hedberg4375f102013-09-25 13:26:10 +03003646static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3647{
3648 struct cmd_lookup match = { NULL, hdev };
3649
3650 if (status) {
3651 u8 mgmt_err = mgmt_status(status);
3652
3653 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3654 cmd_status_rsp, &mgmt_err);
3655 return;
3656 }
3657
3658 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3659 &match);
3660
3661 new_settings(hdev, match.sk);
3662
3663 if (match.sk)
3664 sock_put(match.sk);
3665}
3666
Marcel Holtmann21b51872013-10-10 09:47:53 -07003667static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3668 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003669{
3670 struct mgmt_mode *cp = data;
3671 struct pending_cmd *cmd;
3672 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003673 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003674 int err;
3675
3676 BT_DBG("request for %s", hdev->name);
3677
Johan Hedberge6fe7982013-10-02 15:45:22 +03003678 status = mgmt_le_support(hdev);
3679 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003680 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003681 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003682
3683 if (cp->val != 0x00 && cp->val != 0x01)
3684 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3685 MGMT_STATUS_INVALID_PARAMS);
3686
3687 hci_dev_lock(hdev);
3688
3689 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003690 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003691
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003692 /* The following conditions are ones which mean that we should
3693 * not do any HCI communication but directly send a mgmt
3694 * response to user space (after toggling the flag if
3695 * necessary).
3696 */
3697 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003698 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003699 bool changed = false;
3700
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003701 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3702 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003703 changed = true;
3704 }
3705
3706 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3707 if (err < 0)
3708 goto unlock;
3709
3710 if (changed)
3711 err = new_settings(hdev, sk);
3712
3713 goto unlock;
3714 }
3715
3716 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3717 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3718 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3719 MGMT_STATUS_BUSY);
3720 goto unlock;
3721 }
3722
3723 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3724 if (!cmd) {
3725 err = -ENOMEM;
3726 goto unlock;
3727 }
3728
3729 hci_req_init(&req, hdev);
3730
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003731 if (val)
3732 enable_advertising(&req);
3733 else
3734 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003735
3736 err = hci_req_run(&req, set_advertising_complete);
3737 if (err < 0)
3738 mgmt_pending_remove(cmd);
3739
3740unlock:
3741 hci_dev_unlock(hdev);
3742 return err;
3743}
3744
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003745static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3746 void *data, u16 len)
3747{
3748 struct mgmt_cp_set_static_address *cp = data;
3749 int err;
3750
3751 BT_DBG("%s", hdev->name);
3752
Marcel Holtmann62af4442013-10-02 22:10:32 -07003753 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003754 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003755 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003756
3757 if (hdev_is_powered(hdev))
3758 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3759 MGMT_STATUS_REJECTED);
3760
3761 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3762 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3763 return cmd_status(sk, hdev->id,
3764 MGMT_OP_SET_STATIC_ADDRESS,
3765 MGMT_STATUS_INVALID_PARAMS);
3766
3767 /* Two most significant bits shall be set */
3768 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3769 return cmd_status(sk, hdev->id,
3770 MGMT_OP_SET_STATIC_ADDRESS,
3771 MGMT_STATUS_INVALID_PARAMS);
3772 }
3773
3774 hci_dev_lock(hdev);
3775
3776 bacpy(&hdev->static_addr, &cp->bdaddr);
3777
3778 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3779
3780 hci_dev_unlock(hdev);
3781
3782 return err;
3783}
3784
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003785static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3786 void *data, u16 len)
3787{
3788 struct mgmt_cp_set_scan_params *cp = data;
3789 __u16 interval, window;
3790 int err;
3791
3792 BT_DBG("%s", hdev->name);
3793
3794 if (!lmp_le_capable(hdev))
3795 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3796 MGMT_STATUS_NOT_SUPPORTED);
3797
3798 interval = __le16_to_cpu(cp->interval);
3799
3800 if (interval < 0x0004 || interval > 0x4000)
3801 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3802 MGMT_STATUS_INVALID_PARAMS);
3803
3804 window = __le16_to_cpu(cp->window);
3805
3806 if (window < 0x0004 || window > 0x4000)
3807 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3808 MGMT_STATUS_INVALID_PARAMS);
3809
Marcel Holtmann899e1072013-10-14 09:55:32 -07003810 if (window > interval)
3811 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3812 MGMT_STATUS_INVALID_PARAMS);
3813
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003814 hci_dev_lock(hdev);
3815
3816 hdev->le_scan_interval = interval;
3817 hdev->le_scan_window = window;
3818
3819 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3820
3821 hci_dev_unlock(hdev);
3822
3823 return err;
3824}
3825
Johan Hedberg33e38b32013-03-15 17:07:05 -05003826static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3827{
3828 struct pending_cmd *cmd;
3829
3830 BT_DBG("status 0x%02x", status);
3831
3832 hci_dev_lock(hdev);
3833
3834 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3835 if (!cmd)
3836 goto unlock;
3837
3838 if (status) {
3839 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3840 mgmt_status(status));
3841 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003842 struct mgmt_mode *cp = cmd->param;
3843
3844 if (cp->val)
3845 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3846 else
3847 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3848
Johan Hedberg33e38b32013-03-15 17:07:05 -05003849 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3850 new_settings(hdev, cmd->sk);
3851 }
3852
3853 mgmt_pending_remove(cmd);
3854
3855unlock:
3856 hci_dev_unlock(hdev);
3857}
3858
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003859static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003860 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003861{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003862 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003863 struct pending_cmd *cmd;
3864 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003865 int err;
3866
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003867 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003868
Johan Hedberg56f87902013-10-02 13:43:13 +03003869 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3870 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003871 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3872 MGMT_STATUS_NOT_SUPPORTED);
3873
Johan Hedberga7e80f22013-01-09 16:05:19 +02003874 if (cp->val != 0x00 && cp->val != 0x01)
3875 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3876 MGMT_STATUS_INVALID_PARAMS);
3877
Johan Hedberg5400c042012-02-21 16:40:33 +02003878 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003879 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003880 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003881
3882 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003883 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003884 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003885
3886 hci_dev_lock(hdev);
3887
Johan Hedberg05cbf292013-03-15 17:07:07 -05003888 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3889 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3890 MGMT_STATUS_BUSY);
3891 goto unlock;
3892 }
3893
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003894 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3895 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3896 hdev);
3897 goto unlock;
3898 }
3899
Johan Hedberg33e38b32013-03-15 17:07:05 -05003900 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3901 data, len);
3902 if (!cmd) {
3903 err = -ENOMEM;
3904 goto unlock;
3905 }
3906
3907 hci_req_init(&req, hdev);
3908
Johan Hedberg406d7802013-03-15 17:07:09 -05003909 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003910
3911 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003912 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003913 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003914 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003915 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003916 }
3917
Johan Hedberg33e38b32013-03-15 17:07:05 -05003918unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003919 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003920
Antti Julkuf6422ec2011-06-22 13:11:56 +03003921 return err;
3922}
3923
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003924static void set_bredr_scan(struct hci_request *req)
3925{
3926 struct hci_dev *hdev = req->hdev;
3927 u8 scan = 0;
3928
3929 /* Ensure that fast connectable is disabled. This function will
3930 * not do anything if the page scan parameters are already what
3931 * they should be.
3932 */
3933 write_fast_connectable(req, false);
3934
3935 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3936 scan |= SCAN_PAGE;
3937 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3938 scan |= SCAN_INQUIRY;
3939
3940 if (scan)
3941 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3942}
3943
Johan Hedberg0663ca22013-10-02 13:43:14 +03003944static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3945{
3946 struct pending_cmd *cmd;
3947
3948 BT_DBG("status 0x%02x", status);
3949
3950 hci_dev_lock(hdev);
3951
3952 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3953 if (!cmd)
3954 goto unlock;
3955
3956 if (status) {
3957 u8 mgmt_err = mgmt_status(status);
3958
3959 /* We need to restore the flag if related HCI commands
3960 * failed.
3961 */
3962 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3963
3964 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3965 } else {
3966 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3967 new_settings(hdev, cmd->sk);
3968 }
3969
3970 mgmt_pending_remove(cmd);
3971
3972unlock:
3973 hci_dev_unlock(hdev);
3974}
3975
3976static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3977{
3978 struct mgmt_mode *cp = data;
3979 struct pending_cmd *cmd;
3980 struct hci_request req;
3981 int err;
3982
3983 BT_DBG("request for %s", hdev->name);
3984
3985 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3986 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3987 MGMT_STATUS_NOT_SUPPORTED);
3988
3989 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3990 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3991 MGMT_STATUS_REJECTED);
3992
3993 if (cp->val != 0x00 && cp->val != 0x01)
3994 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3995 MGMT_STATUS_INVALID_PARAMS);
3996
3997 hci_dev_lock(hdev);
3998
3999 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4000 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4001 goto unlock;
4002 }
4003
4004 if (!hdev_is_powered(hdev)) {
4005 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004006 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4007 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4008 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4009 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
4010 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
4011 }
4012
4013 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4014
4015 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4016 if (err < 0)
4017 goto unlock;
4018
4019 err = new_settings(hdev, sk);
4020 goto unlock;
4021 }
4022
4023 /* Reject disabling when powered on */
4024 if (!cp->val) {
4025 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4026 MGMT_STATUS_REJECTED);
4027 goto unlock;
4028 }
4029
4030 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
4031 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4032 MGMT_STATUS_BUSY);
4033 goto unlock;
4034 }
4035
4036 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4037 if (!cmd) {
4038 err = -ENOMEM;
4039 goto unlock;
4040 }
4041
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004042 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03004043 * generates the correct flags.
4044 */
4045 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4046
4047 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004048
4049 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4050 set_bredr_scan(&req);
4051
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004052 /* Since only the advertising data flags will change, there
4053 * is no need to update the scan response data.
4054 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004055 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004056
Johan Hedberg0663ca22013-10-02 13:43:14 +03004057 err = hci_req_run(&req, set_bredr_complete);
4058 if (err < 0)
4059 mgmt_pending_remove(cmd);
4060
4061unlock:
4062 hci_dev_unlock(hdev);
4063 return err;
4064}
4065
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004066static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4067 void *data, u16 len)
4068{
4069 struct mgmt_mode *cp = data;
4070 struct pending_cmd *cmd;
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004071 u8 val, status;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004072 int err;
4073
4074 BT_DBG("request for %s", hdev->name);
4075
4076 status = mgmt_bredr_support(hdev);
4077 if (status)
4078 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4079 status);
4080
Marcel Holtmann5afeac12014-01-10 02:07:27 -08004081 if (!lmp_sc_capable(hdev) &&
4082 !test_bit(HCI_FORCE_SC, &hdev->dev_flags))
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004083 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4084 MGMT_STATUS_NOT_SUPPORTED);
4085
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004086 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004087 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4088 MGMT_STATUS_INVALID_PARAMS);
4089
4090 hci_dev_lock(hdev);
4091
4092 if (!hdev_is_powered(hdev)) {
4093 bool changed;
4094
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004095 if (cp->val) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004096 changed = !test_and_set_bit(HCI_SC_ENABLED,
4097 &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004098 if (cp->val == 0x02)
4099 set_bit(HCI_SC_ONLY, &hdev->dev_flags);
4100 else
4101 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4102 } else {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004103 changed = test_and_clear_bit(HCI_SC_ENABLED,
4104 &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004105 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4106 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004107
4108 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4109 if (err < 0)
4110 goto failed;
4111
4112 if (changed)
4113 err = new_settings(hdev, sk);
4114
4115 goto failed;
4116 }
4117
4118 if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
4119 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4120 MGMT_STATUS_BUSY);
4121 goto failed;
4122 }
4123
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004124 val = !!cp->val;
4125
4126 if (val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
4127 (cp->val == 0x02) == test_bit(HCI_SC_ONLY, &hdev->dev_flags)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004128 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4129 goto failed;
4130 }
4131
4132 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4133 if (!cmd) {
4134 err = -ENOMEM;
4135 goto failed;
4136 }
4137
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004138 err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004139 if (err < 0) {
4140 mgmt_pending_remove(cmd);
4141 goto failed;
4142 }
4143
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004144 if (cp->val == 0x02)
4145 set_bit(HCI_SC_ONLY, &hdev->dev_flags);
4146 else
4147 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4148
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004149failed:
4150 hci_dev_unlock(hdev);
4151 return err;
4152}
4153
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004154static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4155 void *data, u16 len)
4156{
4157 struct mgmt_mode *cp = data;
4158 bool changed;
4159 int err;
4160
4161 BT_DBG("request for %s", hdev->name);
4162
4163 if (cp->val != 0x00 && cp->val != 0x01)
4164 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4165 MGMT_STATUS_INVALID_PARAMS);
4166
4167 hci_dev_lock(hdev);
4168
4169 if (cp->val)
4170 changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
4171 else
4172 changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
4173
4174 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4175 if (err < 0)
4176 goto unlock;
4177
4178 if (changed)
4179 err = new_settings(hdev, sk);
4180
4181unlock:
4182 hci_dev_unlock(hdev);
4183 return err;
4184}
4185
Johan Hedberg41edf162014-02-18 10:19:35 +02004186static bool irk_is_valid(struct mgmt_irk_info *irk)
4187{
4188 switch (irk->addr.type) {
4189 case BDADDR_LE_PUBLIC:
4190 return true;
4191
4192 case BDADDR_LE_RANDOM:
4193 /* Two most significant bits shall be set */
4194 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4195 return false;
4196 return true;
4197 }
4198
4199 return false;
4200}
4201
4202static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4203 u16 len)
4204{
4205 struct mgmt_cp_load_irks *cp = cp_data;
4206 u16 irk_count, expected_len;
4207 int i, err;
4208
4209 BT_DBG("request for %s", hdev->name);
4210
4211 if (!lmp_le_capable(hdev))
4212 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4213 MGMT_STATUS_NOT_SUPPORTED);
4214
4215 irk_count = __le16_to_cpu(cp->irk_count);
4216
4217 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4218 if (expected_len != len) {
4219 BT_ERR("load_irks: expected %u bytes, got %u bytes",
4220 len, expected_len);
4221 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4222 MGMT_STATUS_INVALID_PARAMS);
4223 }
4224
4225 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4226
4227 for (i = 0; i < irk_count; i++) {
4228 struct mgmt_irk_info *key = &cp->irks[i];
4229
4230 if (!irk_is_valid(key))
4231 return cmd_status(sk, hdev->id,
4232 MGMT_OP_LOAD_IRKS,
4233 MGMT_STATUS_INVALID_PARAMS);
4234 }
4235
4236 hci_dev_lock(hdev);
4237
4238 hci_smp_irks_clear(hdev);
4239
4240 for (i = 0; i < irk_count; i++) {
4241 struct mgmt_irk_info *irk = &cp->irks[i];
4242 u8 addr_type;
4243
4244 if (irk->addr.type == BDADDR_LE_PUBLIC)
4245 addr_type = ADDR_LE_DEV_PUBLIC;
4246 else
4247 addr_type = ADDR_LE_DEV_RANDOM;
4248
4249 hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
4250 BDADDR_ANY);
4251 }
4252
4253 set_bit(HCI_RPA_RESOLVING, &hdev->dev_flags);
4254
4255 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
4256
4257 hci_dev_unlock(hdev);
4258
4259 return err;
4260}
4261
Johan Hedberg3f706b72013-01-20 14:27:16 +02004262static bool ltk_is_valid(struct mgmt_ltk_info *key)
4263{
4264 if (key->master != 0x00 && key->master != 0x01)
4265 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004266
4267 switch (key->addr.type) {
4268 case BDADDR_LE_PUBLIC:
4269 return true;
4270
4271 case BDADDR_LE_RANDOM:
4272 /* Two most significant bits shall be set */
4273 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4274 return false;
4275 return true;
4276 }
4277
4278 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004279}
4280
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004281static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004282 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004283{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004284 struct mgmt_cp_load_long_term_keys *cp = cp_data;
4285 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004286 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004287
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004288 BT_DBG("request for %s", hdev->name);
4289
4290 if (!lmp_le_capable(hdev))
4291 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4292 MGMT_STATUS_NOT_SUPPORTED);
4293
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004294 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004295
4296 expected_len = sizeof(*cp) + key_count *
4297 sizeof(struct mgmt_ltk_info);
4298 if (expected_len != len) {
4299 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004300 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004301 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02004302 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004303 }
4304
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004305 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004306
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004307 for (i = 0; i < key_count; i++) {
4308 struct mgmt_ltk_info *key = &cp->keys[i];
4309
Johan Hedberg3f706b72013-01-20 14:27:16 +02004310 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004311 return cmd_status(sk, hdev->id,
4312 MGMT_OP_LOAD_LONG_TERM_KEYS,
4313 MGMT_STATUS_INVALID_PARAMS);
4314 }
4315
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004316 hci_dev_lock(hdev);
4317
4318 hci_smp_ltks_clear(hdev);
4319
4320 for (i = 0; i < key_count; i++) {
4321 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004322 u8 type, addr_type;
4323
4324 if (key->addr.type == BDADDR_LE_PUBLIC)
4325 addr_type = ADDR_LE_DEV_PUBLIC;
4326 else
4327 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004328
4329 if (key->master)
4330 type = HCI_SMP_LTK;
4331 else
4332 type = HCI_SMP_LTK_SLAVE;
4333
Johan Hedberg35d70272014-02-19 14:57:47 +02004334 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type, type,
4335 key->type, key->val, key->enc_size, key->ediv,
4336 key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004337 }
4338
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004339 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4340 NULL, 0);
4341
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004342 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004343
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004344 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004345}
4346
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004347static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004348 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4349 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004350 bool var_len;
4351 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004352} mgmt_handlers[] = {
4353 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004354 { read_version, false, MGMT_READ_VERSION_SIZE },
4355 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4356 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4357 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4358 { set_powered, false, MGMT_SETTING_SIZE },
4359 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4360 { set_connectable, false, MGMT_SETTING_SIZE },
4361 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4362 { set_pairable, false, MGMT_SETTING_SIZE },
4363 { set_link_security, false, MGMT_SETTING_SIZE },
4364 { set_ssp, false, MGMT_SETTING_SIZE },
4365 { set_hs, false, MGMT_SETTING_SIZE },
4366 { set_le, false, MGMT_SETTING_SIZE },
4367 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4368 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4369 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4370 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4371 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4372 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4373 { disconnect, false, MGMT_DISCONNECT_SIZE },
4374 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4375 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4376 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4377 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4378 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4379 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4380 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4381 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4382 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4383 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4384 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4385 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
Marcel Holtmannec109112014-01-10 02:07:30 -08004386 { add_remote_oob_data, true, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
Johan Hedbergbe22b542012-03-01 22:24:41 +02004387 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4388 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4389 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4390 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4391 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4392 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004393 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004394 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004395 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004396 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004397 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004398 { set_secure_conn, false, MGMT_SETTING_SIZE },
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004399 { set_debug_keys, false, MGMT_SETTING_SIZE },
Johan Hedberg41edf162014-02-18 10:19:35 +02004400 { },
4401 { load_irks, true, MGMT_LOAD_IRKS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004402};
4403
4404
Johan Hedberg03811012010-12-08 00:21:06 +02004405int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4406{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004407 void *buf;
4408 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004409 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004410 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004411 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004412 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004413 int err;
4414
4415 BT_DBG("got %zu bytes", msglen);
4416
4417 if (msglen < sizeof(*hdr))
4418 return -EINVAL;
4419
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004420 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004421 if (!buf)
4422 return -ENOMEM;
4423
4424 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4425 err = -EFAULT;
4426 goto done;
4427 }
4428
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004429 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004430 opcode = __le16_to_cpu(hdr->opcode);
4431 index = __le16_to_cpu(hdr->index);
4432 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004433
4434 if (len != msglen - sizeof(*hdr)) {
4435 err = -EINVAL;
4436 goto done;
4437 }
4438
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004439 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004440 hdev = hci_dev_get(index);
4441 if (!hdev) {
4442 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004443 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004444 goto done;
4445 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004446
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004447 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4448 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004449 err = cmd_status(sk, index, opcode,
4450 MGMT_STATUS_INVALID_INDEX);
4451 goto done;
4452 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004453 }
4454
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004455 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004456 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004457 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004458 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004459 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004460 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004461 }
4462
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004463 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004464 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004465 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004466 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004467 goto done;
4468 }
4469
Johan Hedbergbe22b542012-03-01 22:24:41 +02004470 handler = &mgmt_handlers[opcode];
4471
4472 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004473 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004474 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004475 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004476 goto done;
4477 }
4478
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004479 if (hdev)
4480 mgmt_init_hdev(sk, hdev);
4481
4482 cp = buf + sizeof(*hdr);
4483
Johan Hedbergbe22b542012-03-01 22:24:41 +02004484 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004485 if (err < 0)
4486 goto done;
4487
Johan Hedberg03811012010-12-08 00:21:06 +02004488 err = msglen;
4489
4490done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004491 if (hdev)
4492 hci_dev_put(hdev);
4493
Johan Hedberg03811012010-12-08 00:21:06 +02004494 kfree(buf);
4495 return err;
4496}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004497
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004498void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004499{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004500 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004501 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004502
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004503 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004504}
4505
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004506void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004507{
Johan Hedberg5f159032012-03-02 03:13:19 +02004508 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004509
Marcel Holtmann1514b892013-10-06 08:25:01 -07004510 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004511 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004512
Johan Hedberg744cf192011-11-08 20:40:14 +02004513 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004514
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004515 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004516}
4517
Johan Hedberg229ab392013-03-15 17:06:53 -05004518static void powered_complete(struct hci_dev *hdev, u8 status)
4519{
4520 struct cmd_lookup match = { NULL, hdev };
4521
4522 BT_DBG("status 0x%02x", status);
4523
4524 hci_dev_lock(hdev);
4525
4526 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4527
4528 new_settings(hdev, match.sk);
4529
4530 hci_dev_unlock(hdev);
4531
4532 if (match.sk)
4533 sock_put(match.sk);
4534}
4535
Johan Hedberg70da6242013-03-15 17:06:51 -05004536static int powered_update_hci(struct hci_dev *hdev)
4537{
Johan Hedberg890ea892013-03-15 17:06:52 -05004538 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004539 u8 link_sec;
4540
Johan Hedberg890ea892013-03-15 17:06:52 -05004541 hci_req_init(&req, hdev);
4542
Johan Hedberg70da6242013-03-15 17:06:51 -05004543 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4544 !lmp_host_ssp_capable(hdev)) {
4545 u8 ssp = 1;
4546
Johan Hedberg890ea892013-03-15 17:06:52 -05004547 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004548 }
4549
Johan Hedbergc73eee92013-04-19 18:35:21 +03004550 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4551 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004552 struct hci_cp_write_le_host_supported cp;
4553
4554 cp.le = 1;
4555 cp.simul = lmp_le_br_capable(hdev);
4556
4557 /* Check first if we already have the right
4558 * host state (host features set)
4559 */
4560 if (cp.le != lmp_host_le_capable(hdev) ||
4561 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004562 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4563 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004564 }
4565
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004566 if (lmp_le_capable(hdev)) {
4567 /* Set random address to static address if configured */
4568 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4569 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4570 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004571
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004572 /* Make sure the controller has a good default for
4573 * advertising data. This also applies to the case
4574 * where BR/EDR was toggled during the AUTO_OFF phase.
4575 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004576 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004577 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004578 update_scan_rsp_data(&req);
4579 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004580
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004581 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4582 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004583 }
4584
Johan Hedberg70da6242013-03-15 17:06:51 -05004585 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4586 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004587 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4588 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004589
4590 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004591 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4592 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004593 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004594 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004595 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004596 }
4597
Johan Hedberg229ab392013-03-15 17:06:53 -05004598 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004599}
4600
Johan Hedberg744cf192011-11-08 20:40:14 +02004601int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004602{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004603 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004604 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4605 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004606 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004607
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004608 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4609 return 0;
4610
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004611 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004612 if (powered_update_hci(hdev) == 0)
4613 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004614
Johan Hedberg229ab392013-03-15 17:06:53 -05004615 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4616 &match);
4617 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004618 }
4619
Johan Hedberg229ab392013-03-15 17:06:53 -05004620 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4621 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4622
4623 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4624 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4625 zero_cod, sizeof(zero_cod), NULL);
4626
4627new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004628 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004629
4630 if (match.sk)
4631 sock_put(match.sk);
4632
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004633 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004634}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004635
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004636void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004637{
4638 struct pending_cmd *cmd;
4639 u8 status;
4640
4641 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4642 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004643 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004644
4645 if (err == -ERFKILL)
4646 status = MGMT_STATUS_RFKILLED;
4647 else
4648 status = MGMT_STATUS_FAILED;
4649
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004650 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004651
4652 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004653}
4654
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004655void mgmt_discoverable_timeout(struct hci_dev *hdev)
4656{
4657 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004658
4659 hci_dev_lock(hdev);
4660
4661 /* When discoverable timeout triggers, then just make sure
4662 * the limited discoverable flag is cleared. Even in the case
4663 * of a timeout triggered from general discoverable, it is
4664 * safe to unconditionally clear the flag.
4665 */
4666 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004667 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004668
4669 hci_req_init(&req, hdev);
Johan Hedberg4b580612013-10-19 23:38:21 +03004670 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4671 u8 scan = SCAN_PAGE;
4672 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
4673 sizeof(scan), &scan);
4674 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004675 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004676 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004677 hci_req_run(&req, NULL);
4678
4679 hdev->discov_timeout = 0;
4680
Johan Hedberg9a43e252013-10-20 19:00:07 +03004681 new_settings(hdev, NULL);
4682
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004683 hci_dev_unlock(hdev);
4684}
4685
Marcel Holtmann86a75642013-10-15 06:33:54 -07004686void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004687{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004688 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004689
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004690 /* Nothing needed here if there's a pending command since that
4691 * commands request completion callback takes care of everything
4692 * necessary.
4693 */
4694 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004695 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004696
Johan Hedberg9a43e252013-10-20 19:00:07 +03004697 if (discoverable) {
Marcel Holtmann86a75642013-10-15 06:33:54 -07004698 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004699 } else {
4700 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmann86a75642013-10-15 06:33:54 -07004701 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004702 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004703
Johan Hedberg9a43e252013-10-20 19:00:07 +03004704 if (changed) {
4705 struct hci_request req;
4706
4707 /* In case this change in discoverable was triggered by
4708 * a disabling of connectable there could be a need to
4709 * update the advertising flags.
4710 */
4711 hci_req_init(&req, hdev);
4712 update_adv_data(&req);
4713 hci_req_run(&req, NULL);
4714
Marcel Holtmann86a75642013-10-15 06:33:54 -07004715 new_settings(hdev, NULL);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004716 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004717}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004718
Marcel Holtmanna3309162013-10-15 06:33:55 -07004719void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004720{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004721 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004722
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004723 /* Nothing needed here if there's a pending command since that
4724 * commands request completion callback takes care of everything
4725 * necessary.
4726 */
4727 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004728 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004729
Marcel Holtmanna3309162013-10-15 06:33:55 -07004730 if (connectable)
4731 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4732 else
4733 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004734
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004735 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004736 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004737}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004738
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004739void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004740{
Johan Hedbergca69b792011-11-11 18:10:00 +02004741 u8 mgmt_err = mgmt_status(status);
4742
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004743 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004744 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004745 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004746
4747 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004748 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004749 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004750}
4751
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004752void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4753 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004754{
Johan Hedberg86742e12011-11-07 23:13:38 +02004755 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004756
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004757 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004758
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004759 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004760 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004761 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004762 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004763 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004764 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004765
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004766 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004767}
Johan Hedbergf7520542011-01-20 12:34:39 +02004768
Johan Hedbergba74b662014-02-19 14:57:45 +02004769void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004770{
4771 struct mgmt_ev_new_long_term_key ev;
4772
4773 memset(&ev, 0, sizeof(ev));
4774
Marcel Holtmann5192d302014-02-19 17:11:58 -08004775 /* Devices using resolvable or non-resolvable random addresses
4776 * without providing an indentity resolving key don't require
4777 * to store long term keys. Their addresses will change the
4778 * next time around.
4779 *
4780 * Only when a remote device provides an identity address
4781 * make sure the long term key is stored. If the remote
4782 * identity is known, the long term keys are internally
4783 * mapped to the identity address. So allow static random
4784 * and public addresses here.
4785 */
Johan Hedbergba74b662014-02-19 14:57:45 +02004786 if (key->bdaddr_type == ADDR_LE_DEV_RANDOM &&
4787 (key->bdaddr.b[5] & 0xc0) != 0xc0)
4788 ev.store_hint = 0x00;
4789 else
4790 ev.store_hint = 0x01;
4791
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004792 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004793 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Marcel Holtmannd40f3ee2014-01-31 18:42:17 -08004794 ev.key.type = key->authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004795 ev.key.enc_size = key->enc_size;
4796 ev.key.ediv = key->ediv;
4797
4798 if (key->type == HCI_SMP_LTK)
4799 ev.key.master = 1;
4800
4801 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4802 memcpy(ev.key.val, key->val, sizeof(key->val));
4803
Marcel Holtmann083368f2013-10-15 14:26:29 -07004804 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004805}
4806
Johan Hedberg95fbac82014-02-19 15:18:31 +02004807void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk)
4808{
4809 struct mgmt_ev_new_irk ev;
4810
4811 memset(&ev, 0, sizeof(ev));
4812
Marcel Holtmannbab6d1e2014-02-19 11:51:54 -08004813 /* For identity resolving keys from devices that are already
4814 * using a public address or static random address, do not
4815 * ask for storing this key. The identity resolving key really
4816 * is only mandatory for devices using resovlable random
4817 * addresses.
4818 *
4819 * Storing all identity resolving keys has the downside that
4820 * they will be also loaded on next boot of they system. More
4821 * identity resolving keys, means more time during scanning is
4822 * needed to actually resolve these addresses.
4823 */
4824 if (bacmp(&irk->rpa, BDADDR_ANY))
4825 ev.store_hint = 0x01;
4826 else
4827 ev.store_hint = 0x00;
4828
Johan Hedberg95fbac82014-02-19 15:18:31 +02004829 bacpy(&ev.rpa, &irk->rpa);
4830 bacpy(&ev.irk.addr.bdaddr, &irk->bdaddr);
4831 ev.irk.addr.type = link_to_bdaddr(LE_LINK, irk->addr_type);
4832 memcpy(ev.irk.val, irk->val, sizeof(irk->val));
4833
4834 mgmt_event(MGMT_EV_NEW_IRK, hdev, &ev, sizeof(ev), NULL);
4835}
4836
Marcel Holtmann94933992013-10-15 10:26:39 -07004837static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4838 u8 data_len)
4839{
4840 eir[eir_len++] = sizeof(type) + data_len;
4841 eir[eir_len++] = type;
4842 memcpy(&eir[eir_len], data, data_len);
4843 eir_len += data_len;
4844
4845 return eir_len;
4846}
4847
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004848void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4849 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4850 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004851{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004852 char buf[512];
4853 struct mgmt_ev_device_connected *ev = (void *) buf;
4854 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004855
Johan Hedbergb644ba32012-01-17 21:48:47 +02004856 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004857 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004858
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004859 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004860
Johan Hedbergb644ba32012-01-17 21:48:47 +02004861 if (name_len > 0)
4862 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004863 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004864
4865 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004866 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004867 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004868
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004869 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004870
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004871 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4872 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004873}
4874
Johan Hedberg8962ee72011-01-20 12:40:27 +02004875static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4876{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004877 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004878 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004879 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004880
Johan Hedberg88c3df12012-02-09 14:27:38 +02004881 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4882 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004883
Johan Hedbergaee9b212012-02-18 15:07:59 +02004884 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004885 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004886
4887 *sk = cmd->sk;
4888 sock_hold(*sk);
4889
Johan Hedberga664b5b2011-02-19 12:06:02 -03004890 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004891}
4892
Johan Hedberg124f6e32012-02-09 13:50:12 +02004893static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004894{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004895 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004896 struct mgmt_cp_unpair_device *cp = cmd->param;
4897 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004898
4899 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004900 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4901 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004902
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004903 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4904
Johan Hedbergaee9b212012-02-18 15:07:59 +02004905 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004906
4907 mgmt_pending_remove(cmd);
4908}
4909
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004910void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4911 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004912{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004913 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004914 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004915
Andre Guedes57eb7762013-10-30 19:01:41 -03004916 if (link_type != ACL_LINK && link_type != LE_LINK)
4917 return;
4918
Johan Hedberg744cf192011-11-08 20:40:14 +02004919 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004920
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004921 bacpy(&ev.addr.bdaddr, bdaddr);
4922 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4923 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004924
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004925 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004926
4927 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004928 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004929
Johan Hedberg124f6e32012-02-09 13:50:12 +02004930 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004931 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004932}
4933
Marcel Holtmann78929242013-10-06 23:55:47 -07004934void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4935 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004936{
Andre Guedes3655bba2013-10-30 19:01:40 -03004937 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
4938 struct mgmt_cp_disconnect *cp;
Johan Hedberg88c3df12012-02-09 14:27:38 +02004939 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004940 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004941
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004942 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4943 hdev);
4944
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004945 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004946 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004947 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004948
Andre Guedes3655bba2013-10-30 19:01:40 -03004949 cp = cmd->param;
4950
4951 if (bacmp(bdaddr, &cp->addr.bdaddr))
4952 return;
4953
4954 if (cp->addr.type != bdaddr_type)
4955 return;
4956
Johan Hedberg88c3df12012-02-09 14:27:38 +02004957 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes3655bba2013-10-30 19:01:40 -03004958 rp.addr.type = bdaddr_type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004959
Marcel Holtmann78929242013-10-06 23:55:47 -07004960 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4961 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004962
Johan Hedberga664b5b2011-02-19 12:06:02 -03004963 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004964}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004965
Marcel Holtmann445608d2013-10-06 23:55:48 -07004966void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4967 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004968{
4969 struct mgmt_ev_connect_failed ev;
4970
Johan Hedberg4c659c32011-11-07 23:13:39 +02004971 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004972 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004973 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004974
Marcel Holtmann445608d2013-10-06 23:55:48 -07004975 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004976}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004977
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004978void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004979{
4980 struct mgmt_ev_pin_code_request ev;
4981
Johan Hedbergd8457692012-02-17 14:24:57 +02004982 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004983 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004984 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004985
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004986 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004987}
4988
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004989void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4990 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004991{
4992 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004993 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004994
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004995 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004996 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004997 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004998
Johan Hedbergd8457692012-02-17 14:24:57 +02004999 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03005000 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005001
Marcel Holtmanne669cf82013-10-15 14:26:21 -07005002 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
5003 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02005004
Johan Hedberga664b5b2011-02-19 12:06:02 -03005005 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005006}
5007
Marcel Holtmann3eb38522013-10-15 14:26:22 -07005008void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
5009 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02005010{
5011 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005012 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005013
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005014 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005015 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07005016 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02005017
Johan Hedbergd8457692012-02-17 14:24:57 +02005018 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03005019 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03005020
Marcel Holtmann3eb38522013-10-15 14:26:22 -07005021 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
5022 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02005023
Johan Hedberga664b5b2011-02-19 12:06:02 -03005024 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02005025}
Johan Hedberga5c29682011-02-19 12:05:57 -03005026
Johan Hedberg744cf192011-11-08 20:40:14 +02005027int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005028 u8 link_type, u8 addr_type, __le32 value,
5029 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03005030{
5031 struct mgmt_ev_user_confirm_request ev;
5032
Johan Hedberg744cf192011-11-08 20:40:14 +02005033 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03005034
Johan Hedberg272d90d2012-02-09 15:26:12 +02005035 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005036 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07005037 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02005038 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03005039
Johan Hedberg744cf192011-11-08 20:40:14 +02005040 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005041 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03005042}
5043
Johan Hedberg272d90d2012-02-09 15:26:12 +02005044int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03005045 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08005046{
5047 struct mgmt_ev_user_passkey_request ev;
5048
5049 BT_DBG("%s", hdev->name);
5050
Johan Hedberg272d90d2012-02-09 15:26:12 +02005051 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005052 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08005053
5054 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005055 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08005056}
5057
Brian Gix0df4c182011-11-16 13:53:13 -08005058static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03005059 u8 link_type, u8 addr_type, u8 status,
5060 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03005061{
5062 struct pending_cmd *cmd;
5063 struct mgmt_rp_user_confirm_reply rp;
5064 int err;
5065
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005066 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03005067 if (!cmd)
5068 return -ENOENT;
5069
Johan Hedberg272d90d2012-02-09 15:26:12 +02005070 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005071 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02005072 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005073 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03005074
Johan Hedberga664b5b2011-02-19 12:06:02 -03005075 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03005076
5077 return err;
5078}
5079
Johan Hedberg744cf192011-11-08 20:40:14 +02005080int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005081 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03005082{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005083 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005084 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03005085}
5086
Johan Hedberg272d90d2012-02-09 15:26:12 +02005087int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005088 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03005089{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005090 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03005091 status,
5092 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03005093}
Johan Hedberg2a611692011-02-19 12:06:00 -03005094
Brian Gix604086b2011-11-23 08:28:33 -08005095int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005096 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08005097{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005098 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005099 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08005100}
5101
Johan Hedberg272d90d2012-02-09 15:26:12 +02005102int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005103 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08005104{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005105 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03005106 status,
5107 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08005108}
5109
Johan Hedberg92a25252012-09-06 18:39:26 +03005110int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
5111 u8 link_type, u8 addr_type, u32 passkey,
5112 u8 entered)
5113{
5114 struct mgmt_ev_passkey_notify ev;
5115
5116 BT_DBG("%s", hdev->name);
5117
5118 bacpy(&ev.addr.bdaddr, bdaddr);
5119 ev.addr.type = link_to_bdaddr(link_type, addr_type);
5120 ev.passkey = __cpu_to_le32(passkey);
5121 ev.entered = entered;
5122
5123 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
5124}
5125
Marcel Holtmanne5460992013-10-15 14:26:23 -07005126void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5127 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03005128{
5129 struct mgmt_ev_auth_failed ev;
5130
Johan Hedbergbab73cb2012-02-09 16:07:29 +02005131 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005132 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02005133 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03005134
Marcel Holtmanne5460992013-10-15 14:26:23 -07005135 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03005136}
Johan Hedbergb312b1612011-03-16 14:29:37 +02005137
Marcel Holtmann464996a2013-10-15 14:26:24 -07005138void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005139{
5140 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07005141 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005142
5143 if (status) {
5144 u8 mgmt_err = mgmt_status(status);
5145 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005146 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07005147 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005148 }
5149
Marcel Holtmann464996a2013-10-15 14:26:24 -07005150 if (test_bit(HCI_AUTH, &hdev->flags))
5151 changed = !test_and_set_bit(HCI_LINK_SECURITY,
5152 &hdev->dev_flags);
5153 else
5154 changed = test_and_clear_bit(HCI_LINK_SECURITY,
5155 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02005156
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005157 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005158 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005159
Johan Hedberg47990ea2012-02-22 11:58:37 +02005160 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07005161 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005162
5163 if (match.sk)
5164 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005165}
5166
Johan Hedberg890ea892013-03-15 17:06:52 -05005167static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02005168{
Johan Hedberg890ea892013-03-15 17:06:52 -05005169 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02005170 struct hci_cp_write_eir cp;
5171
Johan Hedberg976eb202012-10-24 21:12:01 +03005172 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05005173 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02005174
Johan Hedbergc80da272012-02-22 15:38:48 +02005175 memset(hdev->eir, 0, sizeof(hdev->eir));
5176
Johan Hedbergcacaf522012-02-21 00:52:42 +02005177 memset(&cp, 0, sizeof(cp));
5178
Johan Hedberg890ea892013-03-15 17:06:52 -05005179 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02005180}
5181
Marcel Holtmann3e248562013-10-15 14:26:25 -07005182void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005183{
5184 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05005185 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005186 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005187
5188 if (status) {
5189 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005190
5191 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005192 &hdev->dev_flags)) {
5193 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07005194 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005195 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005196
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005197 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
5198 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07005199 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005200 }
5201
5202 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005203 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005204 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005205 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
5206 if (!changed)
5207 changed = test_and_clear_bit(HCI_HS_ENABLED,
5208 &hdev->dev_flags);
5209 else
5210 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005211 }
5212
5213 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
5214
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005215 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07005216 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005217
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005218 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005219 sock_put(match.sk);
5220
Johan Hedberg890ea892013-03-15 17:06:52 -05005221 hci_req_init(&req, hdev);
5222
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005223 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05005224 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005225 else
Johan Hedberg890ea892013-03-15 17:06:52 -05005226 clear_eir(&req);
5227
5228 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005229}
5230
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005231void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
5232{
5233 struct cmd_lookup match = { NULL, hdev };
5234 bool changed = false;
5235
5236 if (status) {
5237 u8 mgmt_err = mgmt_status(status);
5238
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005239 if (enable) {
5240 if (test_and_clear_bit(HCI_SC_ENABLED,
5241 &hdev->dev_flags))
5242 new_settings(hdev, NULL);
5243 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
5244 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005245
5246 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5247 cmd_status_rsp, &mgmt_err);
5248 return;
5249 }
5250
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005251 if (enable) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005252 changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005253 } else {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005254 changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005255 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
5256 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005257
5258 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5259 settings_rsp, &match);
5260
5261 if (changed)
5262 new_settings(hdev, match.sk);
5263
5264 if (match.sk)
5265 sock_put(match.sk);
5266}
5267
Johan Hedberg92da6092013-03-15 17:06:55 -05005268static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02005269{
5270 struct cmd_lookup *match = data;
5271
Johan Hedberg90e70452012-02-23 23:09:40 +02005272 if (match->sk == NULL) {
5273 match->sk = cmd->sk;
5274 sock_hold(match->sk);
5275 }
Johan Hedberg90e70452012-02-23 23:09:40 +02005276}
5277
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005278void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
5279 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005280{
Johan Hedberg90e70452012-02-23 23:09:40 +02005281 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005282
Johan Hedberg92da6092013-03-15 17:06:55 -05005283 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
5284 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
5285 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02005286
5287 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005288 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
5289 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02005290
5291 if (match.sk)
5292 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005293}
5294
Marcel Holtmann7667da32013-10-15 14:26:27 -07005295void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02005296{
Johan Hedbergb312b1612011-03-16 14:29:37 +02005297 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05005298 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005299
Johan Hedberg13928972013-03-15 17:07:00 -05005300 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07005301 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005302
5303 memset(&ev, 0, sizeof(ev));
5304 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005305 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005306
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005307 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05005308 if (!cmd) {
5309 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02005310
Johan Hedberg13928972013-03-15 17:07:00 -05005311 /* If this is a HCI command related to powering on the
5312 * HCI dev don't send any mgmt signals.
5313 */
5314 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07005315 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005316 }
5317
Marcel Holtmann7667da32013-10-15 14:26:27 -07005318 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
5319 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005320}
Szymon Jancc35938b2011-03-22 13:12:21 +01005321
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005322void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
5323 u8 *randomizer192, u8 *hash256,
5324 u8 *randomizer256, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01005325{
5326 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01005327
Johan Hedberg744cf192011-11-08 20:40:14 +02005328 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01005329
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005330 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01005331 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005332 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01005333
5334 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005335 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
5336 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01005337 } else {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005338 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
5339 hash256 && randomizer256) {
5340 struct mgmt_rp_read_local_oob_ext_data rp;
Szymon Jancc35938b2011-03-22 13:12:21 +01005341
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005342 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
5343 memcpy(rp.randomizer192, randomizer192,
5344 sizeof(rp.randomizer192));
Szymon Jancc35938b2011-03-22 13:12:21 +01005345
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005346 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
5347 memcpy(rp.randomizer256, randomizer256,
5348 sizeof(rp.randomizer256));
5349
5350 cmd_complete(cmd->sk, hdev->id,
5351 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5352 &rp, sizeof(rp));
5353 } else {
5354 struct mgmt_rp_read_local_oob_data rp;
5355
5356 memcpy(rp.hash, hash192, sizeof(rp.hash));
5357 memcpy(rp.randomizer, randomizer192,
5358 sizeof(rp.randomizer));
5359
5360 cmd_complete(cmd->sk, hdev->id,
5361 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5362 &rp, sizeof(rp));
5363 }
Szymon Jancc35938b2011-03-22 13:12:21 +01005364 }
5365
5366 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01005367}
Johan Hedberge17acd42011-03-30 23:57:16 +03005368
Marcel Holtmann901801b2013-10-06 23:55:51 -07005369void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5370 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
5371 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03005372{
Johan Hedberge319d2e2012-01-15 19:51:59 +02005373 char buf[512];
5374 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg5cedbb82014-02-18 21:41:37 +02005375 struct smp_irk *irk;
Johan Hedberg1dc06092012-01-15 21:01:23 +02005376 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03005377
Andre Guedes12602d02013-04-30 15:29:40 -03005378 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005379 return;
Andre Guedes12602d02013-04-30 15:29:40 -03005380
Johan Hedberg1dc06092012-01-15 21:01:23 +02005381 /* Leave 5 bytes for a potential CoD field */
5382 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005383 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03005384
Johan Hedberg1dc06092012-01-15 21:01:23 +02005385 memset(buf, 0, sizeof(buf));
5386
Johan Hedberg5cedbb82014-02-18 21:41:37 +02005387 irk = hci_get_irk(hdev, bdaddr, addr_type);
5388 if (irk) {
5389 bacpy(&ev->addr.bdaddr, &irk->bdaddr);
5390 ev->addr.type = link_to_bdaddr(link_type, irk->addr_type);
5391 } else {
5392 bacpy(&ev->addr.bdaddr, bdaddr);
5393 ev->addr.type = link_to_bdaddr(link_type, addr_type);
5394 }
5395
Johan Hedberge319d2e2012-01-15 19:51:59 +02005396 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02005397 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305398 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02005399 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305400 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03005401
Johan Hedberg1dc06092012-01-15 21:01:23 +02005402 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02005403 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03005404
Johan Hedberg1dc06092012-01-15 21:01:23 +02005405 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
5406 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005407 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005408
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005409 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005410 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03005411
Marcel Holtmann901801b2013-10-06 23:55:51 -07005412 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03005413}
Johan Hedberga88a9652011-03-30 13:18:12 +03005414
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005415void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5416 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03005417{
Johan Hedbergb644ba32012-01-17 21:48:47 +02005418 struct mgmt_ev_device_found *ev;
5419 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
5420 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03005421
Johan Hedbergb644ba32012-01-17 21:48:47 +02005422 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03005423
Johan Hedbergb644ba32012-01-17 21:48:47 +02005424 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03005425
Johan Hedbergb644ba32012-01-17 21:48:47 +02005426 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005427 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005428 ev->rssi = rssi;
5429
5430 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005431 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005432
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005433 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005434
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005435 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03005436}
Johan Hedberg314b2382011-04-27 10:29:57 -04005437
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005438void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04005439{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005440 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02005441 struct pending_cmd *cmd;
5442
Andre Guedes343fb142011-11-22 17:14:19 -03005443 BT_DBG("%s discovering %u", hdev->name, discovering);
5444
Johan Hedberg164a6e72011-11-01 17:06:44 +02005445 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005446 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005447 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005448 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005449
5450 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02005451 u8 type = hdev->discovery.type;
5452
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005453 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
5454 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02005455 mgmt_pending_remove(cmd);
5456 }
5457
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005458 memset(&ev, 0, sizeof(ev));
5459 ev.type = hdev->discovery.type;
5460 ev.discovering = discovering;
5461
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005462 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04005463}
Antti Julku5e762442011-08-25 16:48:02 +03005464
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005465int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005466{
5467 struct pending_cmd *cmd;
5468 struct mgmt_ev_device_blocked ev;
5469
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005470 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005471
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005472 bacpy(&ev.addr.bdaddr, bdaddr);
5473 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005474
Johan Hedberg744cf192011-11-08 20:40:14 +02005475 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005476 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005477}
5478
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005479int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005480{
5481 struct pending_cmd *cmd;
5482 struct mgmt_ev_device_unblocked ev;
5483
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005484 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005485
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005486 bacpy(&ev.addr.bdaddr, bdaddr);
5487 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005488
Johan Hedberg744cf192011-11-08 20:40:14 +02005489 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005490 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005491}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005492
5493static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5494{
5495 BT_DBG("%s status %u", hdev->name, status);
5496
5497 /* Clear the advertising mgmt setting if we failed to re-enable it */
5498 if (status) {
5499 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005500 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005501 }
5502}
5503
5504void mgmt_reenable_advertising(struct hci_dev *hdev)
5505{
5506 struct hci_request req;
5507
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005508 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005509 return;
5510
5511 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5512 return;
5513
5514 hci_req_init(&req, hdev);
5515 enable_advertising(&req);
5516
5517 /* If this fails we have no option but to let user space know
5518 * that we've disabled advertising.
5519 */
5520 if (hci_req_run(&req, adv_enable_complete) < 0) {
5521 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005522 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005523 }
5524}