blob: 747cb9bbc331a553bf9716e95094a97a90a232b4 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070033
34#include "smp.h"
Johan Hedberg03811012010-12-08 00:21:06 +020035
Johan Hedberg2da9c552012-02-17 14:39:28 +020036#define MGMT_VERSION 1
Marcel Holtmann404566442014-01-28 15:39:01 -080037#define MGMT_REVISION 5
Johan Hedberg02d98122010-12-13 21:07:04 +020038
Johan Hedberge70bb2e2012-02-13 16:59:33 +020039static const u16 mgmt_commands[] = {
40 MGMT_OP_READ_INDEX_LIST,
41 MGMT_OP_READ_INFO,
42 MGMT_OP_SET_POWERED,
43 MGMT_OP_SET_DISCOVERABLE,
44 MGMT_OP_SET_CONNECTABLE,
45 MGMT_OP_SET_FAST_CONNECTABLE,
46 MGMT_OP_SET_PAIRABLE,
47 MGMT_OP_SET_LINK_SECURITY,
48 MGMT_OP_SET_SSP,
49 MGMT_OP_SET_HS,
50 MGMT_OP_SET_LE,
51 MGMT_OP_SET_DEV_CLASS,
52 MGMT_OP_SET_LOCAL_NAME,
53 MGMT_OP_ADD_UUID,
54 MGMT_OP_REMOVE_UUID,
55 MGMT_OP_LOAD_LINK_KEYS,
56 MGMT_OP_LOAD_LONG_TERM_KEYS,
57 MGMT_OP_DISCONNECT,
58 MGMT_OP_GET_CONNECTIONS,
59 MGMT_OP_PIN_CODE_REPLY,
60 MGMT_OP_PIN_CODE_NEG_REPLY,
61 MGMT_OP_SET_IO_CAPABILITY,
62 MGMT_OP_PAIR_DEVICE,
63 MGMT_OP_CANCEL_PAIR_DEVICE,
64 MGMT_OP_UNPAIR_DEVICE,
65 MGMT_OP_USER_CONFIRM_REPLY,
66 MGMT_OP_USER_CONFIRM_NEG_REPLY,
67 MGMT_OP_USER_PASSKEY_REPLY,
68 MGMT_OP_USER_PASSKEY_NEG_REPLY,
69 MGMT_OP_READ_LOCAL_OOB_DATA,
70 MGMT_OP_ADD_REMOTE_OOB_DATA,
71 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
72 MGMT_OP_START_DISCOVERY,
73 MGMT_OP_STOP_DISCOVERY,
74 MGMT_OP_CONFIRM_NAME,
75 MGMT_OP_BLOCK_DEVICE,
76 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070077 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030078 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030079 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070080 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070081 MGMT_OP_SET_SCAN_PARAMS,
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -080082 MGMT_OP_SET_SECURE_CONN,
Marcel Holtmann4e39ac82014-01-31 11:55:22 -080083 MGMT_OP_SET_DEBUG_KEYS,
Johan 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,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200109};
110
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800111#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200112
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200113#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
114 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
115
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200116struct pending_cmd {
117 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200118 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200119 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100120 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200121 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300122 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200123};
124
Johan Hedbergca69b792011-11-11 18:10:00 +0200125/* HCI to MGMT error code conversion table */
126static u8 mgmt_status_table[] = {
127 MGMT_STATUS_SUCCESS,
128 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
129 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
130 MGMT_STATUS_FAILED, /* Hardware Failure */
131 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
132 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
Johan Hedbergeadd6632014-01-13 17:15:53 +0200133 MGMT_STATUS_AUTH_FAILED, /* PIN or Key Missing */
Johan Hedbergca69b792011-11-11 18:10:00 +0200134 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
135 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
136 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
137 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
138 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
139 MGMT_STATUS_BUSY, /* Command Disallowed */
140 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
141 MGMT_STATUS_REJECTED, /* Rejected Security */
142 MGMT_STATUS_REJECTED, /* Rejected Personal */
143 MGMT_STATUS_TIMEOUT, /* Host Timeout */
144 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
145 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
146 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
147 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
148 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
149 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
150 MGMT_STATUS_BUSY, /* Repeated Attempts */
151 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
152 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
153 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
154 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
155 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
156 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
157 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
158 MGMT_STATUS_FAILED, /* Unspecified Error */
159 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
160 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
161 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
162 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
163 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
164 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
165 MGMT_STATUS_FAILED, /* Unit Link Key Used */
166 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
167 MGMT_STATUS_TIMEOUT, /* Instant Passed */
168 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
169 MGMT_STATUS_FAILED, /* Transaction Collision */
170 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
171 MGMT_STATUS_REJECTED, /* QoS Rejected */
172 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
173 MGMT_STATUS_REJECTED, /* Insufficient Security */
174 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
175 MGMT_STATUS_BUSY, /* Role Switch Pending */
176 MGMT_STATUS_FAILED, /* Slot Violation */
177 MGMT_STATUS_FAILED, /* Role Switch Failed */
178 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
179 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
180 MGMT_STATUS_BUSY, /* Host Busy Pairing */
181 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
182 MGMT_STATUS_BUSY, /* Controller Busy */
183 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
184 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
185 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
186 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
187 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
188};
189
190static u8 mgmt_status(u8 hci_status)
191{
192 if (hci_status < ARRAY_SIZE(mgmt_status_table))
193 return mgmt_status_table[hci_status];
194
195 return MGMT_STATUS_FAILED;
196}
197
Szymon Janc4e51eae2011-02-25 19:05:48 +0100198static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200199{
200 struct sk_buff *skb;
201 struct mgmt_hdr *hdr;
202 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300203 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200204
Szymon Janc34eb5252011-02-28 14:10:08 +0100205 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200206
Andre Guedes790eff42012-06-07 19:05:46 -0300207 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200208 if (!skb)
209 return -ENOMEM;
210
211 hdr = (void *) skb_put(skb, sizeof(*hdr));
212
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530213 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100214 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200215 hdr->len = cpu_to_le16(sizeof(*ev));
216
217 ev = (void *) skb_put(skb, sizeof(*ev));
218 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200219 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200220
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300221 err = sock_queue_rcv_skb(sk, skb);
222 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223 kfree_skb(skb);
224
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300225 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200226}
227
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200228static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300229 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200230{
231 struct sk_buff *skb;
232 struct mgmt_hdr *hdr;
233 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300234 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200235
236 BT_DBG("sock %p", sk);
237
Andre Guedes790eff42012-06-07 19:05:46 -0300238 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200239 if (!skb)
240 return -ENOMEM;
241
242 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200243
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530244 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100245 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247
Johan Hedberga38528f2011-01-22 06:46:43 +0200248 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200249 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200250 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100251
252 if (rp)
253 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200254
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300255 err = sock_queue_rcv_skb(sk, skb);
256 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200257 kfree_skb(skb);
258
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100259 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200260}
261
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300262static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
263 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200264{
265 struct mgmt_rp_read_version rp;
266
267 BT_DBG("sock %p", sk);
268
269 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200270 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200271
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200272 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300273 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200274}
275
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300276static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
277 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200278{
279 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200280 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
281 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200282 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200283 size_t rp_size;
284 int i, err;
285
286 BT_DBG("sock %p", sk);
287
288 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
289
290 rp = kmalloc(rp_size, GFP_KERNEL);
291 if (!rp)
292 return -ENOMEM;
293
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200294 rp->num_commands = __constant_cpu_to_le16(num_commands);
295 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200296
297 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
298 put_unaligned_le16(mgmt_commands[i], opcode);
299
300 for (i = 0; i < num_events; i++, opcode++)
301 put_unaligned_le16(mgmt_events[i], opcode);
302
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200303 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300304 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200305 kfree(rp);
306
307 return err;
308}
309
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300310static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
311 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200312{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200314 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200315 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300317 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318
319 BT_DBG("sock %p", sk);
320
321 read_lock(&hci_dev_list_lock);
322
323 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300324 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700325 if (d->dev_type == HCI_BREDR)
326 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200327 }
328
Johan Hedberga38528f2011-01-22 06:46:43 +0200329 rp_len = sizeof(*rp) + (2 * count);
330 rp = kmalloc(rp_len, GFP_ATOMIC);
331 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100332 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200333 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100334 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200335
Johan Hedberg476e44c2012-10-19 20:10:46 +0300336 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200337 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200338 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200339 continue;
340
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700341 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
342 continue;
343
Marcel Holtmann1514b892013-10-06 08:25:01 -0700344 if (d->dev_type == HCI_BREDR) {
345 rp->index[count++] = cpu_to_le16(d->id);
346 BT_DBG("Added hci%u", d->id);
347 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348 }
349
Johan Hedberg476e44c2012-10-19 20:10:46 +0300350 rp->num_controllers = cpu_to_le16(count);
351 rp_len = sizeof(*rp) + (2 * count);
352
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200353 read_unlock(&hci_dev_list_lock);
354
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200355 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300356 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200357
Johan Hedberga38528f2011-01-22 06:46:43 +0200358 kfree(rp);
359
360 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200361}
362
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200363static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200364{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200366
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200368 settings |= MGMT_SETTING_PAIRABLE;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800369 settings |= MGMT_SETTING_DEBUG_KEYS;
Johan Hedberg03811012010-12-08 00:21:06 +0200370
Andre Guedesed3fa312012-07-24 15:03:46 -0300371 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300372 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500373 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
374 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300375 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200376 settings |= MGMT_SETTING_BREDR;
377 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700378
379 if (lmp_ssp_capable(hdev)) {
380 settings |= MGMT_SETTING_SSP;
381 settings |= MGMT_SETTING_HS;
382 }
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800383
Marcel Holtmann5afeac142014-01-10 02:07:27 -0800384 if (lmp_sc_capable(hdev) ||
385 test_bit(HCI_FORCE_SC, &hdev->dev_flags))
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800386 settings |= MGMT_SETTING_SECURE_CONN;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700387 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100388
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300389 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200390 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300391 settings |= MGMT_SETTING_ADVERTISING;
392 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200393
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200394 return settings;
395}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200396
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200397static u32 get_current_settings(struct hci_dev *hdev)
398{
399 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200400
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200401 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100402 settings |= MGMT_SETTING_POWERED;
403
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200404 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_CONNECTABLE;
406
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500407 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
408 settings |= MGMT_SETTING_FAST_CONNECTABLE;
409
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200410 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_DISCOVERABLE;
412
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200413 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_PAIRABLE;
415
Johan Hedberg56f87902013-10-02 13:43:13 +0300416 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_BREDR;
418
Johan Hedberg06199cf2012-02-22 16:37:11 +0200419 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200421
Johan Hedberg47990ea2012-02-22 11:58:37 +0200422 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200423 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200424
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200425 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200426 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200427
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200428 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
429 settings |= MGMT_SETTING_HS;
430
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200431 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300432 settings |= MGMT_SETTING_ADVERTISING;
433
Marcel Holtmanne98d2ce2014-01-10 02:07:22 -0800434 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
435 settings |= MGMT_SETTING_SECURE_CONN;
436
Marcel Holtmannb1de97d2014-01-31 11:55:21 -0800437 if (test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags))
438 settings |= MGMT_SETTING_DEBUG_KEYS;
439
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200440 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200441}
442
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300443#define PNP_INFO_SVCLASS_ID 0x1200
444
Johan Hedberg213202e2013-01-27 00:31:33 +0200445static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
446{
447 u8 *ptr = data, *uuids_start = NULL;
448 struct bt_uuid *uuid;
449
450 if (len < 4)
451 return ptr;
452
453 list_for_each_entry(uuid, &hdev->uuids, list) {
454 u16 uuid16;
455
456 if (uuid->size != 16)
457 continue;
458
459 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
460 if (uuid16 < 0x1100)
461 continue;
462
463 if (uuid16 == PNP_INFO_SVCLASS_ID)
464 continue;
465
466 if (!uuids_start) {
467 uuids_start = ptr;
468 uuids_start[0] = 1;
469 uuids_start[1] = EIR_UUID16_ALL;
470 ptr += 2;
471 }
472
473 /* Stop if not enough space to put next UUID */
474 if ((ptr - data) + sizeof(u16) > len) {
475 uuids_start[1] = EIR_UUID16_SOME;
476 break;
477 }
478
479 *ptr++ = (uuid16 & 0x00ff);
480 *ptr++ = (uuid16 & 0xff00) >> 8;
481 uuids_start[0] += sizeof(uuid16);
482 }
483
484 return ptr;
485}
486
Johan Hedbergcdf19632013-01-27 00:31:34 +0200487static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
488{
489 u8 *ptr = data, *uuids_start = NULL;
490 struct bt_uuid *uuid;
491
492 if (len < 6)
493 return ptr;
494
495 list_for_each_entry(uuid, &hdev->uuids, list) {
496 if (uuid->size != 32)
497 continue;
498
499 if (!uuids_start) {
500 uuids_start = ptr;
501 uuids_start[0] = 1;
502 uuids_start[1] = EIR_UUID32_ALL;
503 ptr += 2;
504 }
505
506 /* Stop if not enough space to put next UUID */
507 if ((ptr - data) + sizeof(u32) > len) {
508 uuids_start[1] = EIR_UUID32_SOME;
509 break;
510 }
511
512 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
513 ptr += sizeof(u32);
514 uuids_start[0] += sizeof(u32);
515 }
516
517 return ptr;
518}
519
Johan Hedbergc00d5752013-01-27 00:31:35 +0200520static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
521{
522 u8 *ptr = data, *uuids_start = NULL;
523 struct bt_uuid *uuid;
524
525 if (len < 18)
526 return ptr;
527
528 list_for_each_entry(uuid, &hdev->uuids, list) {
529 if (uuid->size != 128)
530 continue;
531
532 if (!uuids_start) {
533 uuids_start = ptr;
534 uuids_start[0] = 1;
535 uuids_start[1] = EIR_UUID128_ALL;
536 ptr += 2;
537 }
538
539 /* Stop if not enough space to put next UUID */
540 if ((ptr - data) + 16 > len) {
541 uuids_start[1] = EIR_UUID128_SOME;
542 break;
543 }
544
545 memcpy(ptr, uuid->uuid, 16);
546 ptr += 16;
547 uuids_start[0] += 16;
548 }
549
550 return ptr;
551}
552
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300553static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
554{
555 struct pending_cmd *cmd;
556
557 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
558 if (cmd->opcode == opcode)
559 return cmd;
560 }
561
562 return NULL;
563}
564
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700565static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
566{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700567 u8 ad_len = 0;
568 size_t name_len;
569
570 name_len = strlen(hdev->dev_name);
571 if (name_len > 0) {
572 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
573
574 if (name_len > max_len) {
575 name_len = max_len;
576 ptr[1] = EIR_NAME_SHORT;
577 } else
578 ptr[1] = EIR_NAME_COMPLETE;
579
580 ptr[0] = name_len + 1;
581
582 memcpy(ptr + 2, hdev->dev_name, name_len);
583
584 ad_len += (name_len + 2);
585 ptr += (name_len + 2);
586 }
587
588 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700589}
590
591static void update_scan_rsp_data(struct hci_request *req)
592{
593 struct hci_dev *hdev = req->hdev;
594 struct hci_cp_le_set_scan_rsp_data cp;
595 u8 len;
596
Johan Hedberg7751ef12013-10-19 23:38:15 +0300597 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700598 return;
599
600 memset(&cp, 0, sizeof(cp));
601
602 len = create_scan_rsp_data(hdev, cp.data);
603
Johan Hedbergeb438b52013-10-16 15:31:07 +0300604 if (hdev->scan_rsp_data_len == len &&
605 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700606 return;
607
Johan Hedbergeb438b52013-10-16 15:31:07 +0300608 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
609 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700610
611 cp.length = len;
612
613 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
614}
615
Johan Hedberg9a43e252013-10-20 19:00:07 +0300616static u8 get_adv_discov_flags(struct hci_dev *hdev)
617{
618 struct pending_cmd *cmd;
619
620 /* If there's a pending mgmt command the flags will not yet have
621 * their final values, so check for this first.
622 */
623 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
624 if (cmd) {
625 struct mgmt_mode *cp = cmd->param;
626 if (cp->val == 0x01)
627 return LE_AD_GENERAL;
628 else if (cp->val == 0x02)
629 return LE_AD_LIMITED;
630 } else {
631 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
632 return LE_AD_LIMITED;
633 else if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
634 return LE_AD_GENERAL;
635 }
636
637 return 0;
638}
639
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700640static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700641{
642 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700643
Johan Hedberg9a43e252013-10-20 19:00:07 +0300644 flags |= get_adv_discov_flags(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700645
Johan Hedberge8340042014-01-30 11:16:50 -0800646 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700647 flags |= LE_AD_NO_BREDR;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700648
649 if (flags) {
650 BT_DBG("adv flags 0x%02x", flags);
651
652 ptr[0] = 2;
653 ptr[1] = EIR_FLAGS;
654 ptr[2] = flags;
655
656 ad_len += 3;
657 ptr += 3;
658 }
659
660 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
661 ptr[0] = 2;
662 ptr[1] = EIR_TX_POWER;
663 ptr[2] = (u8) hdev->adv_tx_power;
664
665 ad_len += 3;
666 ptr += 3;
667 }
668
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700669 return ad_len;
670}
671
Marcel Holtmann5947f4b2013-10-16 00:16:50 -0700672static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700673{
674 struct hci_dev *hdev = req->hdev;
675 struct hci_cp_le_set_adv_data cp;
676 u8 len;
677
Johan Hedberg10994ce2013-10-19 23:38:16 +0300678 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700679 return;
680
681 memset(&cp, 0, sizeof(cp));
682
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700683 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700684
685 if (hdev->adv_data_len == len &&
686 memcmp(cp.data, hdev->adv_data, len) == 0)
687 return;
688
689 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
690 hdev->adv_data_len = len;
691
692 cp.length = len;
693
694 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
695}
696
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300697static void create_eir(struct hci_dev *hdev, u8 *data)
698{
699 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300700 size_t name_len;
701
702 name_len = strlen(hdev->dev_name);
703
704 if (name_len > 0) {
705 /* EIR Data type */
706 if (name_len > 48) {
707 name_len = 48;
708 ptr[1] = EIR_NAME_SHORT;
709 } else
710 ptr[1] = EIR_NAME_COMPLETE;
711
712 /* EIR Data length */
713 ptr[0] = name_len + 1;
714
715 memcpy(ptr + 2, hdev->dev_name, name_len);
716
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300717 ptr += (name_len + 2);
718 }
719
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100720 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700721 ptr[0] = 2;
722 ptr[1] = EIR_TX_POWER;
723 ptr[2] = (u8) hdev->inq_tx_power;
724
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700725 ptr += 3;
726 }
727
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700728 if (hdev->devid_source > 0) {
729 ptr[0] = 9;
730 ptr[1] = EIR_DEVICE_ID;
731
732 put_unaligned_le16(hdev->devid_source, ptr + 2);
733 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
734 put_unaligned_le16(hdev->devid_product, ptr + 6);
735 put_unaligned_le16(hdev->devid_version, ptr + 8);
736
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700737 ptr += 10;
738 }
739
Johan Hedberg213202e2013-01-27 00:31:33 +0200740 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200741 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200742 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300743}
744
Johan Hedberg890ea892013-03-15 17:06:52 -0500745static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300746{
Johan Hedberg890ea892013-03-15 17:06:52 -0500747 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300748 struct hci_cp_write_eir cp;
749
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200750 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500751 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200752
Johan Hedberg976eb202012-10-24 21:12:01 +0300753 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500754 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300755
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200756 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500757 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300758
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200759 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500760 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300761
762 memset(&cp, 0, sizeof(cp));
763
764 create_eir(hdev, cp.data);
765
766 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500767 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300768
769 memcpy(hdev->eir, cp.data, sizeof(cp.data));
770
Johan Hedberg890ea892013-03-15 17:06:52 -0500771 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300772}
773
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200774static u8 get_service_classes(struct hci_dev *hdev)
775{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300776 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200777 u8 val = 0;
778
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300779 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200780 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200781
782 return val;
783}
784
Johan Hedberg890ea892013-03-15 17:06:52 -0500785static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200786{
Johan Hedberg890ea892013-03-15 17:06:52 -0500787 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200788 u8 cod[3];
789
790 BT_DBG("%s", hdev->name);
791
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200792 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500793 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200794
Johan Hedbergf87ea1d2013-10-19 23:38:17 +0300795 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
796 return;
797
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200798 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500799 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200800
801 cod[0] = hdev->minor_class;
802 cod[1] = hdev->major_class;
803 cod[2] = get_service_classes(hdev);
804
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700805 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
806 cod[1] |= 0x20;
807
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200808 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500809 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200810
Johan Hedberg890ea892013-03-15 17:06:52 -0500811 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200812}
813
Johan Hedberg7d785252011-12-15 00:47:39 +0200814static void service_cache_off(struct work_struct *work)
815{
816 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300817 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500818 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200819
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200820 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200821 return;
822
Johan Hedberg890ea892013-03-15 17:06:52 -0500823 hci_req_init(&req, hdev);
824
Johan Hedberg7d785252011-12-15 00:47:39 +0200825 hci_dev_lock(hdev);
826
Johan Hedberg890ea892013-03-15 17:06:52 -0500827 update_eir(&req);
828 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200829
830 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500831
832 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200833}
834
Johan Hedberg6a919082012-02-28 06:17:26 +0200835static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200836{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200837 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200838 return;
839
Johan Hedberg4f87da82012-03-02 19:55:56 +0200840 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200841
Johan Hedberg4f87da82012-03-02 19:55:56 +0200842 /* Non-mgmt controlled devices get this bit set
843 * implicitly so that pairing works for them, however
844 * for mgmt we require user-space to explicitly enable
845 * it
846 */
847 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200848}
849
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200850static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300851 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200852{
853 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200854
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200855 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200856
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300857 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200858
Johan Hedberg03811012010-12-08 00:21:06 +0200859 memset(&rp, 0, sizeof(rp));
860
Johan Hedberg03811012010-12-08 00:21:06 +0200861 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200862
863 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200864 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200865
866 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
867 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
868
869 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200870
871 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200872 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200873
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300874 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200875
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200876 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300877 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200878}
879
880static void mgmt_pending_free(struct pending_cmd *cmd)
881{
882 sock_put(cmd->sk);
883 kfree(cmd->param);
884 kfree(cmd);
885}
886
887static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300888 struct hci_dev *hdev, void *data,
889 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200890{
891 struct pending_cmd *cmd;
892
Andre Guedes12b94562012-06-07 19:05:45 -0300893 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200894 if (!cmd)
895 return NULL;
896
897 cmd->opcode = opcode;
898 cmd->index = hdev->id;
899
Andre Guedes12b94562012-06-07 19:05:45 -0300900 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200901 if (!cmd->param) {
902 kfree(cmd);
903 return NULL;
904 }
905
906 if (data)
907 memcpy(cmd->param, data, len);
908
909 cmd->sk = sk;
910 sock_hold(sk);
911
912 list_add(&cmd->list, &hdev->mgmt_pending);
913
914 return cmd;
915}
916
917static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300918 void (*cb)(struct pending_cmd *cmd,
919 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300920 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200921{
Andre Guedesa3d09352013-02-01 11:21:30 -0300922 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200923
Andre Guedesa3d09352013-02-01 11:21:30 -0300924 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200925 if (opcode > 0 && cmd->opcode != opcode)
926 continue;
927
928 cb(cmd, data);
929 }
930}
931
Johan Hedberg03811012010-12-08 00:21:06 +0200932static void mgmt_pending_remove(struct pending_cmd *cmd)
933{
934 list_del(&cmd->list);
935 mgmt_pending_free(cmd);
936}
937
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200938static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200939{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200940 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200941
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200942 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300943 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200944}
945
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200946static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300947 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200948{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300949 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200950 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200951 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200952
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200953 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200954
Johan Hedberga7e80f22013-01-09 16:05:19 +0200955 if (cp->val != 0x00 && cp->val != 0x01)
956 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
957 MGMT_STATUS_INVALID_PARAMS);
958
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300959 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200960
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300961 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
962 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
963 MGMT_STATUS_BUSY);
964 goto failed;
965 }
966
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100967 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
968 cancel_delayed_work(&hdev->power_off);
969
970 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200971 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
972 data, len);
973 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100974 goto failed;
975 }
976 }
977
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200978 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200979 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200980 goto failed;
981 }
982
Johan Hedberg03811012010-12-08 00:21:06 +0200983 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
984 if (!cmd) {
985 err = -ENOMEM;
986 goto failed;
987 }
988
989 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200990 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200991 else
Johan Hedberg19202572013-01-14 22:33:51 +0200992 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200993
994 err = 0;
995
996failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300997 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200998 return err;
999}
1000
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001001static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
1002 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001003{
1004 struct sk_buff *skb;
1005 struct mgmt_hdr *hdr;
1006
Andre Guedes790eff42012-06-07 19:05:46 -03001007 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001008 if (!skb)
1009 return -ENOMEM;
1010
1011 hdr = (void *) skb_put(skb, sizeof(*hdr));
1012 hdr->opcode = cpu_to_le16(event);
1013 if (hdev)
1014 hdr->index = cpu_to_le16(hdev->id);
1015 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05301016 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001017 hdr->len = cpu_to_le16(data_len);
1018
1019 if (data)
1020 memcpy(skb_put(skb, data_len), data, data_len);
1021
Marcel Holtmann97e0bde2012-02-22 13:49:28 +01001022 /* Time stamp */
1023 __net_timestamp(skb);
1024
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001025 hci_send_to_control(skb, skip_sk);
1026 kfree_skb(skb);
1027
1028 return 0;
1029}
1030
1031static int new_settings(struct hci_dev *hdev, struct sock *skip)
1032{
1033 __le32 ev;
1034
1035 ev = cpu_to_le32(get_current_settings(hdev));
1036
1037 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1038}
1039
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001040struct cmd_lookup {
1041 struct sock *sk;
1042 struct hci_dev *hdev;
1043 u8 mgmt_status;
1044};
1045
1046static void settings_rsp(struct pending_cmd *cmd, void *data)
1047{
1048 struct cmd_lookup *match = data;
1049
1050 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1051
1052 list_del(&cmd->list);
1053
1054 if (match->sk == NULL) {
1055 match->sk = cmd->sk;
1056 sock_hold(match->sk);
1057 }
1058
1059 mgmt_pending_free(cmd);
1060}
1061
1062static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1063{
1064 u8 *status = data;
1065
1066 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1067 mgmt_pending_remove(cmd);
1068}
1069
Johan Hedberge6fe7982013-10-02 15:45:22 +03001070static u8 mgmt_bredr_support(struct hci_dev *hdev)
1071{
1072 if (!lmp_bredr_capable(hdev))
1073 return MGMT_STATUS_NOT_SUPPORTED;
1074 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1075 return MGMT_STATUS_REJECTED;
1076 else
1077 return MGMT_STATUS_SUCCESS;
1078}
1079
1080static u8 mgmt_le_support(struct hci_dev *hdev)
1081{
1082 if (!lmp_le_capable(hdev))
1083 return MGMT_STATUS_NOT_SUPPORTED;
1084 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1085 return MGMT_STATUS_REJECTED;
1086 else
1087 return MGMT_STATUS_SUCCESS;
1088}
1089
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001090static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1091{
1092 struct pending_cmd *cmd;
1093 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001094 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001095 bool changed;
1096
1097 BT_DBG("status 0x%02x", status);
1098
1099 hci_dev_lock(hdev);
1100
1101 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1102 if (!cmd)
1103 goto unlock;
1104
1105 if (status) {
1106 u8 mgmt_err = mgmt_status(status);
1107 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001108 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001109 goto remove_cmd;
1110 }
1111
1112 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001113 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001114 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1115 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001116
1117 if (hdev->discov_timeout > 0) {
1118 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1119 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1120 to);
1121 }
1122 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001123 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1124 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001125 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001126
1127 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1128
1129 if (changed)
1130 new_settings(hdev, cmd->sk);
1131
Marcel Holtmann970ba522013-10-15 06:33:57 -07001132 /* When the discoverable mode gets changed, make sure
1133 * that class of device has the limited discoverable
1134 * bit correctly set.
1135 */
1136 hci_req_init(&req, hdev);
1137 update_class(&req);
1138 hci_req_run(&req, NULL);
1139
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001140remove_cmd:
1141 mgmt_pending_remove(cmd);
1142
1143unlock:
1144 hci_dev_unlock(hdev);
1145}
1146
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001147static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001148 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001149{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001150 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001151 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001152 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001153 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001154 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001155 int err;
1156
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001157 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001158
Johan Hedberg9a43e252013-10-20 19:00:07 +03001159 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1160 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001161 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberg9a43e252013-10-20 19:00:07 +03001162 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001163
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001164 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga7e80f22013-01-09 16:05:19 +02001165 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1166 MGMT_STATUS_INVALID_PARAMS);
1167
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001168 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001169
1170 /* Disabling discoverable requires that no timeout is set,
1171 * and enabling limited discoverable requires a timeout.
1172 */
1173 if ((cp->val == 0x00 && timeout > 0) ||
1174 (cp->val == 0x02 && timeout == 0))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001175 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001176 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001177
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001178 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001179
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001180 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001181 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001182 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001183 goto failed;
1184 }
1185
1186 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001187 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001188 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001189 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001190 goto failed;
1191 }
1192
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001193 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001194 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001195 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001196 goto failed;
1197 }
1198
1199 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001200 bool changed = false;
1201
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001202 /* Setting limited discoverable when powered off is
1203 * not a valid operation since it requires a timeout
1204 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1205 */
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001206 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1207 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1208 changed = true;
1209 }
1210
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001211 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001212 if (err < 0)
1213 goto failed;
1214
1215 if (changed)
1216 err = new_settings(hdev, sk);
1217
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001218 goto failed;
1219 }
1220
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001221 /* If the current mode is the same, then just update the timeout
1222 * value with the new value. And if only the timeout gets updated,
1223 * then no need for any HCI transactions.
1224 */
1225 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) &&
1226 (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE,
1227 &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001228 cancel_delayed_work(&hdev->discov_off);
1229 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001230
Marcel Holtmann36261542013-10-15 08:28:51 -07001231 if (cp->val && hdev->discov_timeout > 0) {
1232 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001233 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001234 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001235 }
1236
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001237 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001238 goto failed;
1239 }
1240
1241 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1242 if (!cmd) {
1243 err = -ENOMEM;
1244 goto failed;
1245 }
1246
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001247 /* Cancel any potential discoverable timeout that might be
1248 * still active and store new timeout value. The arming of
1249 * the timeout happens in the complete handler.
1250 */
1251 cancel_delayed_work(&hdev->discov_off);
1252 hdev->discov_timeout = timeout;
1253
Johan Hedbergb456f872013-10-19 23:38:22 +03001254 /* Limited discoverable mode */
1255 if (cp->val == 0x02)
1256 set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1257 else
1258 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1259
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001260 hci_req_init(&req, hdev);
1261
Johan Hedberg9a43e252013-10-20 19:00:07 +03001262 /* The procedure for LE-only controllers is much simpler - just
1263 * update the advertising data.
1264 */
1265 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1266 goto update_ad;
1267
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001268 scan = SCAN_PAGE;
1269
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001270 if (cp->val) {
1271 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001272
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001273 if (cp->val == 0x02) {
1274 /* Limited discoverable mode */
Marcel Holtmann33337dc2013-10-23 08:28:01 -07001275 hci_cp.num_iac = min_t(u8, hdev->num_iac, 2);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001276 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1277 hci_cp.iac_lap[1] = 0x8b;
1278 hci_cp.iac_lap[2] = 0x9e;
1279 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1280 hci_cp.iac_lap[4] = 0x8b;
1281 hci_cp.iac_lap[5] = 0x9e;
1282 } else {
1283 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001284 hci_cp.num_iac = 1;
1285 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1286 hci_cp.iac_lap[1] = 0x8b;
1287 hci_cp.iac_lap[2] = 0x9e;
1288 }
1289
1290 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1291 (hci_cp.num_iac * 3) + 1, &hci_cp);
1292
1293 scan |= SCAN_INQUIRY;
1294 } else {
1295 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1296 }
1297
1298 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001299
Johan Hedberg9a43e252013-10-20 19:00:07 +03001300update_ad:
1301 update_adv_data(&req);
1302
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001303 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001304 if (err < 0)
1305 mgmt_pending_remove(cmd);
1306
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001307failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001308 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001309 return err;
1310}
1311
Johan Hedberg406d7802013-03-15 17:07:09 -05001312static void write_fast_connectable(struct hci_request *req, bool enable)
1313{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001314 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001315 struct hci_cp_write_page_scan_activity acp;
1316 u8 type;
1317
Johan Hedberg547003b2013-10-21 16:51:53 +03001318 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1319 return;
1320
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001321 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1322 return;
1323
Johan Hedberg406d7802013-03-15 17:07:09 -05001324 if (enable) {
1325 type = PAGE_SCAN_TYPE_INTERLACED;
1326
1327 /* 160 msec page scan interval */
1328 acp.interval = __constant_cpu_to_le16(0x0100);
1329 } else {
1330 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1331
1332 /* default 1.28 sec page scan */
1333 acp.interval = __constant_cpu_to_le16(0x0800);
1334 }
1335
1336 acp.window = __constant_cpu_to_le16(0x0012);
1337
Johan Hedbergbd98b992013-03-15 17:07:13 -05001338 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1339 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1340 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1341 sizeof(acp), &acp);
1342
1343 if (hdev->page_scan_type != type)
1344 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001345}
1346
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001347static u8 get_adv_type(struct hci_dev *hdev)
1348{
1349 struct pending_cmd *cmd;
1350 bool connectable;
1351
1352 /* If there's a pending mgmt command the flag will not yet have
1353 * it's final value, so check for this first.
1354 */
1355 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1356 if (cmd) {
1357 struct mgmt_mode *cp = cmd->param;
1358 connectable = !!cp->val;
1359 } else {
1360 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1361 }
1362
1363 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1364}
1365
Johan Hedberg95c66e72013-10-14 16:20:06 +03001366static void enable_advertising(struct hci_request *req)
1367{
1368 struct hci_dev *hdev = req->hdev;
1369 struct hci_cp_le_set_adv_param cp;
1370 u8 enable = 0x01;
1371
1372 memset(&cp, 0, sizeof(cp));
1373 cp.min_interval = __constant_cpu_to_le16(0x0800);
1374 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001375 cp.type = get_adv_type(hdev);
Marcel Holtmann79830f62013-10-18 16:38:09 -07001376 cp.own_address_type = hdev->own_addr_type;
Johan Hedberg95c66e72013-10-14 16:20:06 +03001377 cp.channel_map = 0x07;
1378
1379 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1380
1381 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1382}
1383
1384static void disable_advertising(struct hci_request *req)
1385{
1386 u8 enable = 0x00;
1387
1388 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1389}
1390
Johan Hedberg2b76f452013-03-15 17:07:04 -05001391static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1392{
1393 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001394 struct mgmt_mode *cp;
1395 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001396
1397 BT_DBG("status 0x%02x", status);
1398
1399 hci_dev_lock(hdev);
1400
1401 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1402 if (!cmd)
1403 goto unlock;
1404
Johan Hedberg37438c12013-10-14 16:20:05 +03001405 if (status) {
1406 u8 mgmt_err = mgmt_status(status);
1407 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1408 goto remove_cmd;
1409 }
1410
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001411 cp = cmd->param;
1412 if (cp->val)
1413 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1414 else
1415 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1416
Johan Hedberg2b76f452013-03-15 17:07:04 -05001417 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1418
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001419 if (changed)
1420 new_settings(hdev, cmd->sk);
1421
Johan Hedberg37438c12013-10-14 16:20:05 +03001422remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001423 mgmt_pending_remove(cmd);
1424
1425unlock:
1426 hci_dev_unlock(hdev);
1427}
1428
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001429static int set_connectable_update_settings(struct hci_dev *hdev,
1430 struct sock *sk, u8 val)
1431{
1432 bool changed = false;
1433 int err;
1434
1435 if (!!val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1436 changed = true;
1437
1438 if (val) {
1439 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1440 } else {
1441 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1442 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1443 }
1444
1445 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1446 if (err < 0)
1447 return err;
1448
1449 if (changed)
1450 return new_settings(hdev, sk);
1451
1452 return 0;
1453}
1454
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001455static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001456 u16 len)
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001457{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001458 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001459 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001460 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001461 u8 scan;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001462 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001463
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001464 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001465
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001466 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1467 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001468 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001469 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001470
Johan Hedberga7e80f22013-01-09 16:05:19 +02001471 if (cp->val != 0x00 && cp->val != 0x01)
1472 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1473 MGMT_STATUS_INVALID_PARAMS);
1474
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001475 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001476
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001477 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001478 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001479 goto failed;
1480 }
1481
1482 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001483 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001484 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001485 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001486 goto failed;
1487 }
1488
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001489 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1490 if (!cmd) {
1491 err = -ENOMEM;
1492 goto failed;
1493 }
1494
Johan Hedberg2b76f452013-03-15 17:07:04 -05001495 hci_req_init(&req, hdev);
1496
Johan Hedberg9a43e252013-10-20 19:00:07 +03001497 /* If BR/EDR is not enabled and we disable advertising as a
1498 * by-product of disabling connectable, we need to update the
1499 * advertising flags.
1500 */
1501 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
1502 if (!cp->val) {
1503 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1504 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1505 }
1506 update_adv_data(&req);
1507 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001508 if (cp->val) {
1509 scan = SCAN_PAGE;
1510 } else {
1511 scan = 0;
1512
1513 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001514 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001515 cancel_delayed_work(&hdev->discov_off);
1516 }
1517
1518 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1519 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001520
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001521 /* If we're going from non-connectable to connectable or
1522 * vice-versa when fast connectable is enabled ensure that fast
1523 * connectable gets disabled. write_fast_connectable won't do
1524 * anything if the page scan parameters are already what they
1525 * should be.
1526 */
1527 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001528 write_fast_connectable(&req, false);
1529
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001530 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1531 hci_conn_num(hdev, LE_LINK) == 0) {
1532 disable_advertising(&req);
1533 enable_advertising(&req);
1534 }
1535
Johan Hedberg2b76f452013-03-15 17:07:04 -05001536 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001537 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001538 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001539 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03001540 err = set_connectable_update_settings(hdev, sk,
1541 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03001542 goto failed;
1543 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001544
1545failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001546 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001547 return err;
1548}
1549
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001550static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001551 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001552{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001553 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001554 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001555 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001556
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001557 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001558
Johan Hedberga7e80f22013-01-09 16:05:19 +02001559 if (cp->val != 0x00 && cp->val != 0x01)
1560 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1561 MGMT_STATUS_INVALID_PARAMS);
1562
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001563 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001564
1565 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001566 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001567 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001568 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001569
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001570 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001571 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001572 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001573
Marcel Holtmann55594352013-10-06 16:11:57 -07001574 if (changed)
1575 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001576
Marcel Holtmann55594352013-10-06 16:11:57 -07001577unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001578 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001579 return err;
1580}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001581
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001582static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1583 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001584{
1585 struct mgmt_mode *cp = data;
1586 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001587 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001588 int err;
1589
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001590 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001591
Johan Hedberge6fe7982013-10-02 15:45:22 +03001592 status = mgmt_bredr_support(hdev);
1593 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001594 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001595 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001596
Johan Hedberga7e80f22013-01-09 16:05:19 +02001597 if (cp->val != 0x00 && cp->val != 0x01)
1598 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1599 MGMT_STATUS_INVALID_PARAMS);
1600
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001601 hci_dev_lock(hdev);
1602
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001603 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001604 bool changed = false;
1605
1606 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001607 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001608 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1609 changed = true;
1610 }
1611
1612 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1613 if (err < 0)
1614 goto failed;
1615
1616 if (changed)
1617 err = new_settings(hdev, sk);
1618
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001619 goto failed;
1620 }
1621
1622 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001623 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001624 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001625 goto failed;
1626 }
1627
1628 val = !!cp->val;
1629
1630 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1631 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1632 goto failed;
1633 }
1634
1635 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1636 if (!cmd) {
1637 err = -ENOMEM;
1638 goto failed;
1639 }
1640
1641 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1642 if (err < 0) {
1643 mgmt_pending_remove(cmd);
1644 goto failed;
1645 }
1646
1647failed:
1648 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001649 return err;
1650}
1651
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001652static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001653{
1654 struct mgmt_mode *cp = data;
1655 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001656 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001657 int err;
1658
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001659 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001660
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001661 status = mgmt_bredr_support(hdev);
1662 if (status)
1663 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1664
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001665 if (!lmp_ssp_capable(hdev))
1666 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1667 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001668
Johan Hedberga7e80f22013-01-09 16:05:19 +02001669 if (cp->val != 0x00 && cp->val != 0x01)
1670 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1671 MGMT_STATUS_INVALID_PARAMS);
1672
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001673 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001674
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001675 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001676 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001677
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001678 if (cp->val) {
1679 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1680 &hdev->dev_flags);
1681 } else {
1682 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1683 &hdev->dev_flags);
1684 if (!changed)
1685 changed = test_and_clear_bit(HCI_HS_ENABLED,
1686 &hdev->dev_flags);
1687 else
1688 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001689 }
1690
1691 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1692 if (err < 0)
1693 goto failed;
1694
1695 if (changed)
1696 err = new_settings(hdev, sk);
1697
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001698 goto failed;
1699 }
1700
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001701 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1702 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001703 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1704 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001705 goto failed;
1706 }
1707
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001708 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001709 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1710 goto failed;
1711 }
1712
1713 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1714 if (!cmd) {
1715 err = -ENOMEM;
1716 goto failed;
1717 }
1718
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001719 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001720 if (err < 0) {
1721 mgmt_pending_remove(cmd);
1722 goto failed;
1723 }
1724
1725failed:
1726 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001727 return err;
1728}
1729
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001730static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001731{
1732 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001733 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001734 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001735 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001736
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001737 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001738
Johan Hedberge6fe7982013-10-02 15:45:22 +03001739 status = mgmt_bredr_support(hdev);
1740 if (status)
1741 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001742
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001743 if (!lmp_ssp_capable(hdev))
1744 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1745 MGMT_STATUS_NOT_SUPPORTED);
1746
1747 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1748 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1749 MGMT_STATUS_REJECTED);
1750
Johan Hedberga7e80f22013-01-09 16:05:19 +02001751 if (cp->val != 0x00 && cp->val != 0x01)
1752 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1753 MGMT_STATUS_INVALID_PARAMS);
1754
Marcel Holtmannee392692013-10-01 22:59:23 -07001755 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001756
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001757 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001758 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001759 } else {
1760 if (hdev_is_powered(hdev)) {
1761 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1762 MGMT_STATUS_REJECTED);
1763 goto unlock;
1764 }
1765
Marcel Holtmannee392692013-10-01 22:59:23 -07001766 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001767 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001768
1769 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1770 if (err < 0)
1771 goto unlock;
1772
1773 if (changed)
1774 err = new_settings(hdev, sk);
1775
1776unlock:
1777 hci_dev_unlock(hdev);
1778 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001779}
1780
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001781static void le_enable_complete(struct hci_dev *hdev, u8 status)
1782{
1783 struct cmd_lookup match = { NULL, hdev };
1784
1785 if (status) {
1786 u8 mgmt_err = mgmt_status(status);
1787
1788 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1789 &mgmt_err);
1790 return;
1791 }
1792
1793 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1794
1795 new_settings(hdev, match.sk);
1796
1797 if (match.sk)
1798 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001799
1800 /* Make sure the controller has a good default for
1801 * advertising data. Restrict the update to when LE
1802 * has actually been enabled. During power on, the
1803 * update in powered_update_hci will take care of it.
1804 */
1805 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1806 struct hci_request req;
1807
1808 hci_dev_lock(hdev);
1809
1810 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001811 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07001812 update_scan_rsp_data(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001813 hci_req_run(&req, NULL);
1814
1815 hci_dev_unlock(hdev);
1816 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001817}
1818
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001819static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001820{
1821 struct mgmt_mode *cp = data;
1822 struct hci_cp_write_le_host_supported hci_cp;
1823 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001824 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001825 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001826 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001827
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001828 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001829
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001830 if (!lmp_le_capable(hdev))
1831 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1832 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001833
Johan Hedberga7e80f22013-01-09 16:05:19 +02001834 if (cp->val != 0x00 && cp->val != 0x01)
1835 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1836 MGMT_STATUS_INVALID_PARAMS);
1837
Johan Hedbergc73eee92013-04-19 18:35:21 +03001838 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001839 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001840 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1841 MGMT_STATUS_REJECTED);
1842
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001843 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001844
1845 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001846 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001847
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001848 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001849 bool changed = false;
1850
1851 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1852 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1853 changed = true;
1854 }
1855
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001856 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1857 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001858 changed = true;
1859 }
1860
Johan Hedberg06199cf2012-02-22 16:37:11 +02001861 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1862 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001863 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001864
1865 if (changed)
1866 err = new_settings(hdev, sk);
1867
Johan Hedberg1de028c2012-02-29 19:55:35 -08001868 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001869 }
1870
Johan Hedberg4375f102013-09-25 13:26:10 +03001871 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1872 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001873 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001874 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001875 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001876 }
1877
1878 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1879 if (!cmd) {
1880 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001881 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001882 }
1883
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001884 hci_req_init(&req, hdev);
1885
Johan Hedberg06199cf2012-02-22 16:37:11 +02001886 memset(&hci_cp, 0, sizeof(hci_cp));
1887
1888 if (val) {
1889 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001890 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001891 } else {
1892 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1893 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001894 }
1895
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001896 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1897 &hci_cp);
1898
1899 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301900 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001901 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001902
Johan Hedberg1de028c2012-02-29 19:55:35 -08001903unlock:
1904 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001905 return err;
1906}
1907
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001908/* This is a helper function to test for pending mgmt commands that can
1909 * cause CoD or EIR HCI commands. We can only allow one such pending
1910 * mgmt command at a time since otherwise we cannot easily track what
1911 * the current values are, will be, and based on that calculate if a new
1912 * HCI command needs to be sent and if yes with what value.
1913 */
1914static bool pending_eir_or_class(struct hci_dev *hdev)
1915{
1916 struct pending_cmd *cmd;
1917
1918 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1919 switch (cmd->opcode) {
1920 case MGMT_OP_ADD_UUID:
1921 case MGMT_OP_REMOVE_UUID:
1922 case MGMT_OP_SET_DEV_CLASS:
1923 case MGMT_OP_SET_POWERED:
1924 return true;
1925 }
1926 }
1927
1928 return false;
1929}
1930
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001931static const u8 bluetooth_base_uuid[] = {
1932 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1933 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1934};
1935
1936static u8 get_uuid_size(const u8 *uuid)
1937{
1938 u32 val;
1939
1940 if (memcmp(uuid, bluetooth_base_uuid, 12))
1941 return 128;
1942
1943 val = get_unaligned_le32(&uuid[12]);
1944 if (val > 0xffff)
1945 return 32;
1946
1947 return 16;
1948}
1949
Johan Hedberg92da6092013-03-15 17:06:55 -05001950static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1951{
1952 struct pending_cmd *cmd;
1953
1954 hci_dev_lock(hdev);
1955
1956 cmd = mgmt_pending_find(mgmt_op, hdev);
1957 if (!cmd)
1958 goto unlock;
1959
1960 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1961 hdev->dev_class, 3);
1962
1963 mgmt_pending_remove(cmd);
1964
1965unlock:
1966 hci_dev_unlock(hdev);
1967}
1968
1969static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1970{
1971 BT_DBG("status 0x%02x", status);
1972
1973 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1974}
1975
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001976static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001977{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001978 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001979 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001980 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001981 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001982 int err;
1983
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001984 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001985
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001986 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001987
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001988 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001989 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001990 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001991 goto failed;
1992 }
1993
Andre Guedes92c4c202012-06-07 19:05:44 -03001994 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001995 if (!uuid) {
1996 err = -ENOMEM;
1997 goto failed;
1998 }
1999
2000 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002001 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02002002 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002003
Johan Hedbergde66aa62013-01-27 00:31:27 +02002004 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002005
Johan Hedberg890ea892013-03-15 17:06:52 -05002006 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002007
Johan Hedberg890ea892013-03-15 17:06:52 -05002008 update_class(&req);
2009 update_eir(&req);
2010
Johan Hedberg92da6092013-03-15 17:06:55 -05002011 err = hci_req_run(&req, add_uuid_complete);
2012 if (err < 0) {
2013 if (err != -ENODATA)
2014 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002015
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002016 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002017 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002018 goto failed;
2019 }
2020
2021 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002022 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002023 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002024 goto failed;
2025 }
2026
2027 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002028
2029failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002030 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002031 return err;
2032}
2033
Johan Hedberg24b78d02012-02-23 23:24:30 +02002034static bool enable_service_cache(struct hci_dev *hdev)
2035{
2036 if (!hdev_is_powered(hdev))
2037 return false;
2038
2039 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002040 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2041 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002042 return true;
2043 }
2044
2045 return false;
2046}
2047
Johan Hedberg92da6092013-03-15 17:06:55 -05002048static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
2049{
2050 BT_DBG("status 0x%02x", status);
2051
2052 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2053}
2054
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002055static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002056 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002057{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002058 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002059 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002060 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002061 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 -05002062 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002063 int err, found;
2064
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002065 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002066
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002067 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002068
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002069 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002070 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002071 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002072 goto unlock;
2073 }
2074
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002075 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
Johan Hedberg35f74982014-02-18 17:14:32 +02002076 hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002077
Johan Hedberg24b78d02012-02-23 23:24:30 +02002078 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002079 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002080 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002081 goto unlock;
2082 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002083
Johan Hedberg9246a862012-02-23 21:33:16 +02002084 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002085 }
2086
2087 found = 0;
2088
Johan Hedberg056341c2013-01-27 00:31:30 +02002089 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002090 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2091 continue;
2092
2093 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002094 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002095 found++;
2096 }
2097
2098 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002099 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002100 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002101 goto unlock;
2102 }
2103
Johan Hedberg9246a862012-02-23 21:33:16 +02002104update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002105 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002106
Johan Hedberg890ea892013-03-15 17:06:52 -05002107 update_class(&req);
2108 update_eir(&req);
2109
Johan Hedberg92da6092013-03-15 17:06:55 -05002110 err = hci_req_run(&req, remove_uuid_complete);
2111 if (err < 0) {
2112 if (err != -ENODATA)
2113 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002114
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002115 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002116 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002117 goto unlock;
2118 }
2119
2120 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002121 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002122 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002123 goto unlock;
2124 }
2125
2126 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002127
2128unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002129 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002130 return err;
2131}
2132
Johan Hedberg92da6092013-03-15 17:06:55 -05002133static void set_class_complete(struct hci_dev *hdev, u8 status)
2134{
2135 BT_DBG("status 0x%02x", status);
2136
2137 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2138}
2139
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002140static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002141 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002142{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002143 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002144 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002145 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002146 int err;
2147
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002148 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002149
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002150 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002151 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2152 MGMT_STATUS_NOT_SUPPORTED);
2153
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002154 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002155
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002156 if (pending_eir_or_class(hdev)) {
2157 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2158 MGMT_STATUS_BUSY);
2159 goto unlock;
2160 }
2161
2162 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2163 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2164 MGMT_STATUS_INVALID_PARAMS);
2165 goto unlock;
2166 }
2167
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002168 hdev->major_class = cp->major;
2169 hdev->minor_class = cp->minor;
2170
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002171 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002172 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002173 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002174 goto unlock;
2175 }
2176
Johan Hedberg890ea892013-03-15 17:06:52 -05002177 hci_req_init(&req, hdev);
2178
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002179 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002180 hci_dev_unlock(hdev);
2181 cancel_delayed_work_sync(&hdev->service_cache);
2182 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002183 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002184 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002185
Johan Hedberg890ea892013-03-15 17:06:52 -05002186 update_class(&req);
2187
Johan Hedberg92da6092013-03-15 17:06:55 -05002188 err = hci_req_run(&req, set_class_complete);
2189 if (err < 0) {
2190 if (err != -ENODATA)
2191 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002192
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002193 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002194 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002195 goto unlock;
2196 }
2197
2198 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002199 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002200 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002201 goto unlock;
2202 }
2203
2204 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002205
Johan Hedbergb5235a62012-02-21 14:32:24 +02002206unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002207 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002208 return err;
2209}
2210
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002211static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002212 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002213{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002214 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002215 u16 key_count, expected_len;
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002216 bool changed;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002217 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002218
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002219 BT_DBG("request for %s", hdev->name);
2220
2221 if (!lmp_bredr_capable(hdev))
2222 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2223 MGMT_STATUS_NOT_SUPPORTED);
2224
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002225 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002226
Johan Hedberg86742e12011-11-07 23:13:38 +02002227 expected_len = sizeof(*cp) + key_count *
2228 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002229 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002230 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002231 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002232 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002233 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002234 }
2235
Johan Hedberg4ae14302013-01-20 14:27:13 +02002236 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2237 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2238 MGMT_STATUS_INVALID_PARAMS);
2239
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002240 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002241 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002242
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002243 for (i = 0; i < key_count; i++) {
2244 struct mgmt_link_key_info *key = &cp->keys[i];
2245
Marcel Holtmann8e991132014-01-10 02:07:25 -08002246 if (key->addr.type != BDADDR_BREDR || key->type > 0x08)
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002247 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2248 MGMT_STATUS_INVALID_PARAMS);
2249 }
2250
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002251 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002252
2253 hci_link_keys_clear(hdev);
2254
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002255 if (cp->debug_keys)
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002256 changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002257 else
Marcel Holtmannb1de97d2014-01-31 11:55:21 -08002258 changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
2259
2260 if (changed)
2261 new_settings(hdev, NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002262
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002263 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002264 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002265
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002266 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002267 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002268 }
2269
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002270 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002271
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002272 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002273
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002274 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002275}
2276
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002277static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002278 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002279{
2280 struct mgmt_ev_device_unpaired ev;
2281
2282 bacpy(&ev.addr.bdaddr, bdaddr);
2283 ev.addr.type = addr_type;
2284
2285 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002286 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002287}
2288
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002289static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002290 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002291{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002292 struct mgmt_cp_unpair_device *cp = data;
2293 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002294 struct hci_cp_disconnect dc;
2295 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002296 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002297 int err;
2298
Johan Hedberga8a1d192011-11-10 15:54:38 +02002299 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002300 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2301 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002302
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002303 if (!bdaddr_type_is_valid(cp->addr.type))
2304 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2305 MGMT_STATUS_INVALID_PARAMS,
2306 &rp, sizeof(rp));
2307
Johan Hedberg118da702013-01-20 14:27:20 +02002308 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2309 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2310 MGMT_STATUS_INVALID_PARAMS,
2311 &rp, sizeof(rp));
2312
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002313 hci_dev_lock(hdev);
2314
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002315 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002316 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002317 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002318 goto unlock;
2319 }
2320
Johan Hedberge0b2b272014-02-18 17:14:31 +02002321 if (cp->addr.type == BDADDR_BREDR) {
Johan Hedberg124f6e32012-02-09 13:50:12 +02002322 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
Johan Hedberge0b2b272014-02-18 17:14:31 +02002323 } else {
2324 u8 addr_type;
2325
2326 if (cp->addr.type == BDADDR_LE_PUBLIC)
2327 addr_type = ADDR_LE_DEV_PUBLIC;
2328 else
2329 addr_type = ADDR_LE_DEV_RANDOM;
2330
Johan Hedberga7ec7332014-02-18 17:14:35 +02002331 hci_remove_irk(hdev, &cp->addr.bdaddr, addr_type);
2332
Johan Hedberge0b2b272014-02-18 17:14:31 +02002333 err = hci_remove_ltk(hdev, &cp->addr.bdaddr, addr_type);
2334 }
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002335
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002336 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002337 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002338 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002339 goto unlock;
2340 }
2341
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002342 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002343 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002344 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002345 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002346 else
2347 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002348 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002349 } else {
2350 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002351 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002352
Johan Hedberga8a1d192011-11-10 15:54:38 +02002353 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002354 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002355 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002356 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002357 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002358 }
2359
Johan Hedberg124f6e32012-02-09 13:50:12 +02002360 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002361 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002362 if (!cmd) {
2363 err = -ENOMEM;
2364 goto unlock;
2365 }
2366
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002367 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002368 dc.reason = 0x13; /* Remote User Terminated Connection */
2369 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2370 if (err < 0)
2371 mgmt_pending_remove(cmd);
2372
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002373unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002374 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002375 return err;
2376}
2377
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002378static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002379 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002380{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002381 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002382 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002383 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002384 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002385 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002386 int err;
2387
2388 BT_DBG("");
2389
Johan Hedberg06a63b12013-01-20 14:27:21 +02002390 memset(&rp, 0, sizeof(rp));
2391 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2392 rp.addr.type = cp->addr.type;
2393
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002394 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002395 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2396 MGMT_STATUS_INVALID_PARAMS,
2397 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002398
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002399 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002400
2401 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002402 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2403 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002404 goto failed;
2405 }
2406
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002407 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002408 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2409 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002410 goto failed;
2411 }
2412
Andre Guedes591f47f2012-04-24 21:02:49 -03002413 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002414 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2415 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002416 else
2417 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002418
Vishal Agarwalf9607272012-06-13 05:32:43 +05302419 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002420 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2421 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002422 goto failed;
2423 }
2424
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002425 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002426 if (!cmd) {
2427 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002428 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002429 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002430
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002431 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002432 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002433
2434 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2435 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002436 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002437
2438failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002439 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002440 return err;
2441}
2442
Andre Guedes57c14772012-04-24 21:02:50 -03002443static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002444{
2445 switch (link_type) {
2446 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002447 switch (addr_type) {
2448 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002449 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002450
Johan Hedberg48264f02011-11-09 13:58:58 +02002451 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002452 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002453 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002454 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002455
Johan Hedberg4c659c32011-11-07 23:13:39 +02002456 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002457 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002458 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002459 }
2460}
2461
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002462static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2463 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002464{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002465 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002466 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002467 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002468 int err;
2469 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002470
2471 BT_DBG("");
2472
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002473 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002474
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002475 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002476 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002477 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002478 goto unlock;
2479 }
2480
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002481 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002482 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2483 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002484 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002485 }
2486
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002487 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002488 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002489 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002490 err = -ENOMEM;
2491 goto unlock;
2492 }
2493
Johan Hedberg2784eb42011-01-21 13:56:35 +02002494 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002495 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002496 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2497 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002498 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002499 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002500 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002501 continue;
2502 i++;
2503 }
2504
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002505 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002506
Johan Hedberg4c659c32011-11-07 23:13:39 +02002507 /* Recalculate length in case of filtered SCO connections, etc */
2508 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002509
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002510 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002511 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002512
Johan Hedberga38528f2011-01-22 06:46:43 +02002513 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002514
2515unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002516 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002517 return err;
2518}
2519
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002520static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002521 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002522{
2523 struct pending_cmd *cmd;
2524 int err;
2525
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002526 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002527 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002528 if (!cmd)
2529 return -ENOMEM;
2530
Johan Hedbergd8457692012-02-17 14:24:57 +02002531 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002532 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002533 if (err < 0)
2534 mgmt_pending_remove(cmd);
2535
2536 return err;
2537}
2538
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002539static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002540 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002541{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002542 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002543 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002544 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002545 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002546 int err;
2547
2548 BT_DBG("");
2549
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002550 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002551
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002552 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002553 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002554 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002555 goto failed;
2556 }
2557
Johan Hedbergd8457692012-02-17 14:24:57 +02002558 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002559 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002560 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002561 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002562 goto failed;
2563 }
2564
2565 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002566 struct mgmt_cp_pin_code_neg_reply ncp;
2567
2568 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002569
2570 BT_ERR("PIN code is not 16 bytes long");
2571
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002572 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002573 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002574 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002575 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002576
2577 goto failed;
2578 }
2579
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002580 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002581 if (!cmd) {
2582 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002583 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002584 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002585
Johan Hedbergd8457692012-02-17 14:24:57 +02002586 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002587 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002588 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002589
2590 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2591 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002592 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002593
2594failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002595 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002596 return err;
2597}
2598
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002599static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2600 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002601{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002602 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002603
2604 BT_DBG("");
2605
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002606 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002607
2608 hdev->io_capability = cp->io_capability;
2609
2610 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002611 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002612
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002613 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002614
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002615 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2616 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002617}
2618
Gustavo Padovan6039aa732012-05-23 04:04:18 -03002619static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002620{
2621 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002622 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002623
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002624 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002625 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2626 continue;
2627
Johan Hedberge9a416b2011-02-19 12:05:56 -03002628 if (cmd->user_data != conn)
2629 continue;
2630
2631 return cmd;
2632 }
2633
2634 return NULL;
2635}
2636
2637static void pairing_complete(struct pending_cmd *cmd, u8 status)
2638{
2639 struct mgmt_rp_pair_device rp;
2640 struct hci_conn *conn = cmd->user_data;
2641
Johan Hedbergba4e5642011-11-11 00:07:34 +02002642 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002643 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002644
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002645 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002646 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002647
2648 /* So we don't get further callbacks for this connection */
2649 conn->connect_cfm_cb = NULL;
2650 conn->security_cfm_cb = NULL;
2651 conn->disconn_cfm_cb = NULL;
2652
David Herrmann76a68ba2013-04-06 20:28:37 +02002653 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002654
Johan Hedberga664b5b2011-02-19 12:06:02 -03002655 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002656}
2657
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002658void mgmt_smp_complete(struct hci_conn *conn, bool complete)
2659{
2660 u8 status = complete ? MGMT_STATUS_SUCCESS : MGMT_STATUS_FAILED;
2661 struct pending_cmd *cmd;
2662
2663 cmd = find_pairing(conn);
2664 if (cmd)
2665 pairing_complete(cmd, status);
2666}
2667
Johan Hedberge9a416b2011-02-19 12:05:56 -03002668static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2669{
2670 struct pending_cmd *cmd;
2671
2672 BT_DBG("status %u", status);
2673
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002674 cmd = find_pairing(conn);
2675 if (!cmd)
2676 BT_DBG("Unable to find a pending command");
2677 else
Johan Hedberge2113262012-02-18 15:20:03 +02002678 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002679}
2680
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002681static void le_pairing_complete_cb(struct hci_conn *conn, u8 status)
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302682{
2683 struct pending_cmd *cmd;
2684
2685 BT_DBG("status %u", status);
2686
2687 if (!status)
2688 return;
2689
2690 cmd = find_pairing(conn);
2691 if (!cmd)
2692 BT_DBG("Unable to find a pending command");
2693 else
2694 pairing_complete(cmd, mgmt_status(status));
2695}
2696
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002697static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002698 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002699{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002700 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002701 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002702 struct pending_cmd *cmd;
2703 u8 sec_level, auth_type;
2704 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002705 int err;
2706
2707 BT_DBG("");
2708
Szymon Jancf950a30e2013-01-18 12:48:07 +01002709 memset(&rp, 0, sizeof(rp));
2710 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2711 rp.addr.type = cp->addr.type;
2712
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002713 if (!bdaddr_type_is_valid(cp->addr.type))
2714 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2715 MGMT_STATUS_INVALID_PARAMS,
2716 &rp, sizeof(rp));
2717
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002718 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002719
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002720 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002721 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2722 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002723 goto unlock;
2724 }
2725
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002726 sec_level = BT_SECURITY_MEDIUM;
2727 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002728 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002729 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002730 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002731
Andre Guedes591f47f2012-04-24 21:02:49 -03002732 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002733 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2734 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002735 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002736 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2737 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002738
Ville Tervo30e76272011-02-22 16:10:53 -03002739 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002740 int status;
2741
2742 if (PTR_ERR(conn) == -EBUSY)
2743 status = MGMT_STATUS_BUSY;
2744 else
2745 status = MGMT_STATUS_CONNECT_FAILED;
2746
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002747 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002748 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002749 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002750 goto unlock;
2751 }
2752
2753 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002754 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002755 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002756 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002757 goto unlock;
2758 }
2759
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002760 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002761 if (!cmd) {
2762 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002763 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002764 goto unlock;
2765 }
2766
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002767 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002768 if (cp->addr.type == BDADDR_BREDR) {
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002769 conn->connect_cfm_cb = pairing_complete_cb;
Johan Hedbergf4a407b2014-02-18 21:41:34 +02002770 conn->security_cfm_cb = pairing_complete_cb;
2771 conn->disconn_cfm_cb = pairing_complete_cb;
2772 } else {
2773 conn->connect_cfm_cb = le_pairing_complete_cb;
2774 conn->security_cfm_cb = le_pairing_complete_cb;
2775 conn->disconn_cfm_cb = le_pairing_complete_cb;
2776 }
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002777
Johan Hedberge9a416b2011-02-19 12:05:56 -03002778 conn->io_capability = cp->io_cap;
2779 cmd->user_data = conn;
2780
2781 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002782 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002783 pairing_complete(cmd, 0);
2784
2785 err = 0;
2786
2787unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002788 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002789 return err;
2790}
2791
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002792static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2793 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002794{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002795 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002796 struct pending_cmd *cmd;
2797 struct hci_conn *conn;
2798 int err;
2799
2800 BT_DBG("");
2801
Johan Hedberg28424702012-02-02 04:02:29 +02002802 hci_dev_lock(hdev);
2803
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002804 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002805 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002806 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002807 goto unlock;
2808 }
2809
Johan Hedberg28424702012-02-02 04:02:29 +02002810 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2811 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002812 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002813 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002814 goto unlock;
2815 }
2816
2817 conn = cmd->user_data;
2818
2819 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002820 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002821 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002822 goto unlock;
2823 }
2824
2825 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2826
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002827 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002828 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002829unlock:
2830 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002831 return err;
2832}
2833
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002834static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002835 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002836 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002837{
Johan Hedberga5c29682011-02-19 12:05:57 -03002838 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002839 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002840 int err;
2841
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002842 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002843
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002844 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002845 err = cmd_complete(sk, hdev->id, mgmt_op,
2846 MGMT_STATUS_NOT_POWERED, addr,
2847 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002848 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002849 }
2850
Johan Hedberg1707c602013-03-15 17:07:15 -05002851 if (addr->type == BDADDR_BREDR)
2852 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002853 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002854 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002855
Johan Hedberg272d90d2012-02-09 15:26:12 +02002856 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002857 err = cmd_complete(sk, hdev->id, mgmt_op,
2858 MGMT_STATUS_NOT_CONNECTED, addr,
2859 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002860 goto done;
2861 }
2862
Johan Hedberg1707c602013-03-15 17:07:15 -05002863 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002864 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002865 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002866
Brian Gix5fe57d92011-12-21 16:12:13 -08002867 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002868 err = cmd_complete(sk, hdev->id, mgmt_op,
2869 MGMT_STATUS_SUCCESS, addr,
2870 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002871 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002872 err = cmd_complete(sk, hdev->id, mgmt_op,
2873 MGMT_STATUS_FAILED, addr,
2874 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002875
Brian Gix47c15e22011-11-16 13:53:14 -08002876 goto done;
2877 }
2878
Johan Hedberg1707c602013-03-15 17:07:15 -05002879 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002880 if (!cmd) {
2881 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002882 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002883 }
2884
Brian Gix0df4c182011-11-16 13:53:13 -08002885 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002886 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2887 struct hci_cp_user_passkey_reply cp;
2888
Johan Hedberg1707c602013-03-15 17:07:15 -05002889 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002890 cp.passkey = passkey;
2891 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2892 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002893 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2894 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002895
Johan Hedberga664b5b2011-02-19 12:06:02 -03002896 if (err < 0)
2897 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002898
Brian Gix0df4c182011-11-16 13:53:13 -08002899done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002900 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002901 return err;
2902}
2903
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302904static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2905 void *data, u16 len)
2906{
2907 struct mgmt_cp_pin_code_neg_reply *cp = data;
2908
2909 BT_DBG("");
2910
Johan Hedberg1707c602013-03-15 17:07:15 -05002911 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302912 MGMT_OP_PIN_CODE_NEG_REPLY,
2913 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2914}
2915
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002916static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2917 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002918{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002919 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002920
2921 BT_DBG("");
2922
2923 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002924 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002925 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002926
Johan Hedberg1707c602013-03-15 17:07:15 -05002927 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002928 MGMT_OP_USER_CONFIRM_REPLY,
2929 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002930}
2931
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002932static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002933 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002934{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002935 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002936
2937 BT_DBG("");
2938
Johan Hedberg1707c602013-03-15 17:07:15 -05002939 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002940 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2941 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002942}
2943
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002944static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2945 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002946{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002947 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002948
2949 BT_DBG("");
2950
Johan Hedberg1707c602013-03-15 17:07:15 -05002951 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002952 MGMT_OP_USER_PASSKEY_REPLY,
2953 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002954}
2955
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002956static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002957 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002958{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002959 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002960
2961 BT_DBG("");
2962
Johan Hedberg1707c602013-03-15 17:07:15 -05002963 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002964 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2965 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002966}
2967
Johan Hedberg13928972013-03-15 17:07:00 -05002968static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002969{
Johan Hedberg13928972013-03-15 17:07:00 -05002970 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002971 struct hci_cp_write_local_name cp;
2972
Johan Hedberg13928972013-03-15 17:07:00 -05002973 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002974
Johan Hedberg890ea892013-03-15 17:06:52 -05002975 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002976}
2977
Johan Hedberg13928972013-03-15 17:07:00 -05002978static void set_name_complete(struct hci_dev *hdev, u8 status)
2979{
2980 struct mgmt_cp_set_local_name *cp;
2981 struct pending_cmd *cmd;
2982
2983 BT_DBG("status 0x%02x", status);
2984
2985 hci_dev_lock(hdev);
2986
2987 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2988 if (!cmd)
2989 goto unlock;
2990
2991 cp = cmd->param;
2992
2993 if (status)
2994 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2995 mgmt_status(status));
2996 else
2997 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2998 cp, sizeof(*cp));
2999
3000 mgmt_pending_remove(cmd);
3001
3002unlock:
3003 hci_dev_unlock(hdev);
3004}
3005
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003006static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003007 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003008{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003009 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003010 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05003011 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003012 int err;
3013
3014 BT_DBG("");
3015
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003016 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003017
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05003018 /* If the old values are the same as the new ones just return a
3019 * direct command complete event.
3020 */
3021 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
3022 !memcmp(hdev->short_name, cp->short_name,
3023 sizeof(hdev->short_name))) {
3024 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
3025 data, len);
3026 goto failed;
3027 }
3028
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003029 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003030
Johan Hedbergb5235a62012-02-21 14:32:24 +02003031 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02003032 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003033
3034 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003035 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003036 if (err < 0)
3037 goto failed;
3038
3039 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003040 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003041
Johan Hedbergb5235a62012-02-21 14:32:24 +02003042 goto failed;
3043 }
3044
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003045 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003046 if (!cmd) {
3047 err = -ENOMEM;
3048 goto failed;
3049 }
3050
Johan Hedberg13928972013-03-15 17:07:00 -05003051 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3052
Johan Hedberg890ea892013-03-15 17:06:52 -05003053 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003054
3055 if (lmp_bredr_capable(hdev)) {
3056 update_name(&req);
3057 update_eir(&req);
3058 }
3059
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003060 /* The name is stored in the scan response data and so
3061 * no need to udpate the advertising data here.
3062 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003063 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003064 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003065
Johan Hedberg13928972013-03-15 17:07:00 -05003066 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003067 if (err < 0)
3068 mgmt_pending_remove(cmd);
3069
3070failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003071 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003072 return err;
3073}
3074
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003075static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003076 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003077{
Szymon Jancc35938b2011-03-22 13:12:21 +01003078 struct pending_cmd *cmd;
3079 int err;
3080
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003081 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003082
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003083 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003084
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003085 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003086 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003087 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003088 goto unlock;
3089 }
3090
Andre Guedes9a1a1992012-07-24 15:03:48 -03003091 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003092 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003093 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003094 goto unlock;
3095 }
3096
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003097 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003098 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003099 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003100 goto unlock;
3101 }
3102
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003103 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003104 if (!cmd) {
3105 err = -ENOMEM;
3106 goto unlock;
3107 }
3108
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08003109 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags))
3110 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_EXT_DATA,
3111 0, NULL);
3112 else
3113 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3114
Szymon Jancc35938b2011-03-22 13:12:21 +01003115 if (err < 0)
3116 mgmt_pending_remove(cmd);
3117
3118unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003119 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003120 return err;
3121}
3122
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003123static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003124 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003125{
Szymon Janc2763eda2011-03-22 13:12:22 +01003126 int err;
3127
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003128 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003129
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003130 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003131
Marcel Holtmannec109112014-01-10 02:07:30 -08003132 if (len == MGMT_ADD_REMOTE_OOB_DATA_SIZE) {
3133 struct mgmt_cp_add_remote_oob_data *cp = data;
3134 u8 status;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003135
Marcel Holtmannec109112014-01-10 02:07:30 -08003136 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr,
3137 cp->hash, cp->randomizer);
3138 if (err < 0)
3139 status = MGMT_STATUS_FAILED;
3140 else
3141 status = MGMT_STATUS_SUCCESS;
3142
3143 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3144 status, &cp->addr, sizeof(cp->addr));
3145 } else if (len == MGMT_ADD_REMOTE_OOB_EXT_DATA_SIZE) {
3146 struct mgmt_cp_add_remote_oob_ext_data *cp = data;
3147 u8 status;
3148
3149 err = hci_add_remote_oob_ext_data(hdev, &cp->addr.bdaddr,
3150 cp->hash192,
3151 cp->randomizer192,
3152 cp->hash256,
3153 cp->randomizer256);
3154 if (err < 0)
3155 status = MGMT_STATUS_FAILED;
3156 else
3157 status = MGMT_STATUS_SUCCESS;
3158
3159 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3160 status, &cp->addr, sizeof(cp->addr));
3161 } else {
3162 BT_ERR("add_remote_oob_data: invalid length of %u bytes", len);
3163 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
3164 MGMT_STATUS_INVALID_PARAMS);
3165 }
Szymon Janc2763eda2011-03-22 13:12:22 +01003166
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003167 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003168 return err;
3169}
3170
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003171static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003172 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003173{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003174 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003175 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003176 int err;
3177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003178 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003179
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003180 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003181
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003182 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003183 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003184 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003185 else
Szymon Janca6785be2012-12-13 15:11:21 +01003186 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003187
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003188 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003189 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003190
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003191 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003192 return err;
3193}
3194
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003195static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3196{
3197 struct pending_cmd *cmd;
3198 u8 type;
3199 int err;
3200
3201 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3202
3203 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3204 if (!cmd)
3205 return -ENOENT;
3206
3207 type = hdev->discovery.type;
3208
3209 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3210 &type, sizeof(type));
3211 mgmt_pending_remove(cmd);
3212
3213 return err;
3214}
3215
Andre Guedes7c307722013-04-30 15:29:28 -03003216static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3217{
3218 BT_DBG("status %d", status);
3219
3220 if (status) {
3221 hci_dev_lock(hdev);
3222 mgmt_start_discovery_failed(hdev, status);
3223 hci_dev_unlock(hdev);
3224 return;
3225 }
3226
3227 hci_dev_lock(hdev);
3228 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3229 hci_dev_unlock(hdev);
3230
3231 switch (hdev->discovery.type) {
3232 case DISCOV_TYPE_LE:
3233 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003234 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003235 break;
3236
3237 case DISCOV_TYPE_INTERLEAVED:
3238 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003239 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003240 break;
3241
3242 case DISCOV_TYPE_BREDR:
3243 break;
3244
3245 default:
3246 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3247 }
3248}
3249
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003250static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003251 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003252{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003253 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003254 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003255 struct hci_cp_le_set_scan_param param_cp;
3256 struct hci_cp_le_set_scan_enable enable_cp;
3257 struct hci_cp_inquiry inq_cp;
3258 struct hci_request req;
3259 /* General inquiry access code (GIAC) */
3260 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003261 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003262 int err;
3263
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003264 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003265
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003266 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003267
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003268 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003269 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003270 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003271 goto failed;
3272 }
3273
Andre Guedes642be6c2012-03-21 00:03:37 -03003274 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3275 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3276 MGMT_STATUS_BUSY);
3277 goto failed;
3278 }
3279
Johan Hedbergff9ef572012-01-04 14:23:45 +02003280 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003281 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003282 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003283 goto failed;
3284 }
3285
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003286 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003287 if (!cmd) {
3288 err = -ENOMEM;
3289 goto failed;
3290 }
3291
Andre Guedes4aab14e2012-02-17 20:39:36 -03003292 hdev->discovery.type = cp->type;
3293
Andre Guedes7c307722013-04-30 15:29:28 -03003294 hci_req_init(&req, hdev);
3295
Andre Guedes4aab14e2012-02-17 20:39:36 -03003296 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003297 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003298 status = mgmt_bredr_support(hdev);
3299 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003300 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003301 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003302 mgmt_pending_remove(cmd);
3303 goto failed;
3304 }
3305
Andre Guedes7c307722013-04-30 15:29:28 -03003306 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3307 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3308 MGMT_STATUS_BUSY);
3309 mgmt_pending_remove(cmd);
3310 goto failed;
3311 }
3312
3313 hci_inquiry_cache_flush(hdev);
3314
3315 memset(&inq_cp, 0, sizeof(inq_cp));
3316 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003317 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003318 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003319 break;
3320
3321 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003322 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003323 status = mgmt_le_support(hdev);
3324 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003325 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003326 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003327 mgmt_pending_remove(cmd);
3328 goto failed;
3329 }
3330
Andre Guedes7c307722013-04-30 15:29:28 -03003331 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003332 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003333 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3334 MGMT_STATUS_NOT_SUPPORTED);
3335 mgmt_pending_remove(cmd);
3336 goto failed;
3337 }
3338
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003339 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003340 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3341 MGMT_STATUS_REJECTED);
3342 mgmt_pending_remove(cmd);
3343 goto failed;
3344 }
3345
3346 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3347 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3348 MGMT_STATUS_BUSY);
3349 mgmt_pending_remove(cmd);
3350 goto failed;
3351 }
3352
3353 memset(&param_cp, 0, sizeof(param_cp));
3354 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003355 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3356 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmann79830f62013-10-18 16:38:09 -07003357 param_cp.own_address_type = hdev->own_addr_type;
Andre Guedes7c307722013-04-30 15:29:28 -03003358 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3359 &param_cp);
3360
3361 memset(&enable_cp, 0, sizeof(enable_cp));
3362 enable_cp.enable = LE_SCAN_ENABLE;
3363 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3364 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3365 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003366 break;
3367
Andre Guedesf39799f2012-02-17 20:39:35 -03003368 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003369 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3370 MGMT_STATUS_INVALID_PARAMS);
3371 mgmt_pending_remove(cmd);
3372 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003373 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003374
Andre Guedes7c307722013-04-30 15:29:28 -03003375 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003376 if (err < 0)
3377 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003378 else
3379 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003380
3381failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003382 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003383 return err;
3384}
3385
Andre Guedes1183fdc2013-04-30 15:29:35 -03003386static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3387{
3388 struct pending_cmd *cmd;
3389 int err;
3390
3391 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3392 if (!cmd)
3393 return -ENOENT;
3394
3395 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3396 &hdev->discovery.type, sizeof(hdev->discovery.type));
3397 mgmt_pending_remove(cmd);
3398
3399 return err;
3400}
3401
Andre Guedes0e05bba2013-04-30 15:29:33 -03003402static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3403{
3404 BT_DBG("status %d", status);
3405
3406 hci_dev_lock(hdev);
3407
3408 if (status) {
3409 mgmt_stop_discovery_failed(hdev, status);
3410 goto unlock;
3411 }
3412
3413 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3414
3415unlock:
3416 hci_dev_unlock(hdev);
3417}
3418
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003419static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003420 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003421{
Johan Hedbergd9306502012-02-20 23:25:18 +02003422 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003423 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003424 struct hci_cp_remote_name_req_cancel cp;
3425 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003426 struct hci_request req;
3427 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003428 int err;
3429
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003430 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003431
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003432 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003433
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003434 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003435 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003436 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3437 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003438 goto unlock;
3439 }
3440
3441 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003442 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003443 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3444 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003445 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003446 }
3447
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003448 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003449 if (!cmd) {
3450 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003451 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003452 }
3453
Andre Guedes0e05bba2013-04-30 15:29:33 -03003454 hci_req_init(&req, hdev);
3455
Andre Guedese0d9727e2012-03-20 15:15:36 -03003456 switch (hdev->discovery.state) {
3457 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003458 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3459 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3460 } else {
3461 cancel_delayed_work(&hdev->le_scan_disable);
3462
3463 memset(&enable_cp, 0, sizeof(enable_cp));
3464 enable_cp.enable = LE_SCAN_DISABLE;
3465 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3466 sizeof(enable_cp), &enable_cp);
3467 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003468
Andre Guedese0d9727e2012-03-20 15:15:36 -03003469 break;
3470
3471 case DISCOVERY_RESOLVING:
3472 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003473 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003474 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003475 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003476 err = cmd_complete(sk, hdev->id,
3477 MGMT_OP_STOP_DISCOVERY, 0,
3478 &mgmt_cp->type,
3479 sizeof(mgmt_cp->type));
3480 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3481 goto unlock;
3482 }
3483
3484 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003485 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3486 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003487
3488 break;
3489
3490 default:
3491 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003492
3493 mgmt_pending_remove(cmd);
3494 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3495 MGMT_STATUS_FAILED, &mgmt_cp->type,
3496 sizeof(mgmt_cp->type));
3497 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003498 }
3499
Andre Guedes0e05bba2013-04-30 15:29:33 -03003500 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003501 if (err < 0)
3502 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003503 else
3504 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003505
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003506unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003507 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003508 return err;
3509}
3510
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003511static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003512 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003513{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003514 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003515 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003516 int err;
3517
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003518 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003519
Johan Hedberg561aafb2012-01-04 13:31:59 +02003520 hci_dev_lock(hdev);
3521
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003522 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003523 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003524 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003525 goto failed;
3526 }
3527
Johan Hedberga198e7b2012-02-17 14:27:06 +02003528 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003529 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003530 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003531 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003532 goto failed;
3533 }
3534
3535 if (cp->name_known) {
3536 e->name_state = NAME_KNOWN;
3537 list_del(&e->list);
3538 } else {
3539 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003540 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003541 }
3542
Johan Hedberge3846622013-01-09 15:29:33 +02003543 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3544 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003545
3546failed:
3547 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003548 return err;
3549}
3550
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003551static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003552 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003553{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003554 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003555 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003556 int err;
3557
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003558 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003559
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003560 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003561 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3562 MGMT_STATUS_INVALID_PARAMS,
3563 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003564
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003565 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003566
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003567 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003568 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003569 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003570 else
Szymon Janca6785be2012-12-13 15:11:21 +01003571 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003572
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003573 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003574 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003575
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003576 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003577
3578 return err;
3579}
3580
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003581static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003582 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003583{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003584 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003585 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003586 int err;
3587
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003588 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003589
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003590 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003591 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3592 MGMT_STATUS_INVALID_PARAMS,
3593 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003594
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003595 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003596
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003597 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003598 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003599 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003600 else
Szymon Janca6785be2012-12-13 15:11:21 +01003601 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003602
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003603 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003604 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003605
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003606 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003607
3608 return err;
3609}
3610
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003611static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3612 u16 len)
3613{
3614 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003615 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003616 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003617 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003618
3619 BT_DBG("%s", hdev->name);
3620
Szymon Jancc72d4b82012-03-16 16:02:57 +01003621 source = __le16_to_cpu(cp->source);
3622
3623 if (source > 0x0002)
3624 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3625 MGMT_STATUS_INVALID_PARAMS);
3626
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003627 hci_dev_lock(hdev);
3628
Szymon Jancc72d4b82012-03-16 16:02:57 +01003629 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003630 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3631 hdev->devid_product = __le16_to_cpu(cp->product);
3632 hdev->devid_version = __le16_to_cpu(cp->version);
3633
3634 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3635
Johan Hedberg890ea892013-03-15 17:06:52 -05003636 hci_req_init(&req, hdev);
3637 update_eir(&req);
3638 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003639
3640 hci_dev_unlock(hdev);
3641
3642 return err;
3643}
3644
Johan Hedberg4375f102013-09-25 13:26:10 +03003645static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3646{
3647 struct cmd_lookup match = { NULL, hdev };
3648
3649 if (status) {
3650 u8 mgmt_err = mgmt_status(status);
3651
3652 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3653 cmd_status_rsp, &mgmt_err);
3654 return;
3655 }
3656
3657 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3658 &match);
3659
3660 new_settings(hdev, match.sk);
3661
3662 if (match.sk)
3663 sock_put(match.sk);
3664}
3665
Marcel Holtmann21b51872013-10-10 09:47:53 -07003666static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3667 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003668{
3669 struct mgmt_mode *cp = data;
3670 struct pending_cmd *cmd;
3671 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003672 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003673 int err;
3674
3675 BT_DBG("request for %s", hdev->name);
3676
Johan Hedberge6fe7982013-10-02 15:45:22 +03003677 status = mgmt_le_support(hdev);
3678 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003679 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003680 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003681
3682 if (cp->val != 0x00 && cp->val != 0x01)
3683 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3684 MGMT_STATUS_INVALID_PARAMS);
3685
3686 hci_dev_lock(hdev);
3687
3688 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003689 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003690
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003691 /* The following conditions are ones which mean that we should
3692 * not do any HCI communication but directly send a mgmt
3693 * response to user space (after toggling the flag if
3694 * necessary).
3695 */
3696 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003697 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003698 bool changed = false;
3699
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003700 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3701 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003702 changed = true;
3703 }
3704
3705 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3706 if (err < 0)
3707 goto unlock;
3708
3709 if (changed)
3710 err = new_settings(hdev, sk);
3711
3712 goto unlock;
3713 }
3714
3715 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3716 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3717 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3718 MGMT_STATUS_BUSY);
3719 goto unlock;
3720 }
3721
3722 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3723 if (!cmd) {
3724 err = -ENOMEM;
3725 goto unlock;
3726 }
3727
3728 hci_req_init(&req, hdev);
3729
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003730 if (val)
3731 enable_advertising(&req);
3732 else
3733 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003734
3735 err = hci_req_run(&req, set_advertising_complete);
3736 if (err < 0)
3737 mgmt_pending_remove(cmd);
3738
3739unlock:
3740 hci_dev_unlock(hdev);
3741 return err;
3742}
3743
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003744static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3745 void *data, u16 len)
3746{
3747 struct mgmt_cp_set_static_address *cp = data;
3748 int err;
3749
3750 BT_DBG("%s", hdev->name);
3751
Marcel Holtmann62af4442013-10-02 22:10:32 -07003752 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003753 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003754 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003755
3756 if (hdev_is_powered(hdev))
3757 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3758 MGMT_STATUS_REJECTED);
3759
3760 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3761 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3762 return cmd_status(sk, hdev->id,
3763 MGMT_OP_SET_STATIC_ADDRESS,
3764 MGMT_STATUS_INVALID_PARAMS);
3765
3766 /* Two most significant bits shall be set */
3767 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3768 return cmd_status(sk, hdev->id,
3769 MGMT_OP_SET_STATIC_ADDRESS,
3770 MGMT_STATUS_INVALID_PARAMS);
3771 }
3772
3773 hci_dev_lock(hdev);
3774
3775 bacpy(&hdev->static_addr, &cp->bdaddr);
3776
3777 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3778
3779 hci_dev_unlock(hdev);
3780
3781 return err;
3782}
3783
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003784static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3785 void *data, u16 len)
3786{
3787 struct mgmt_cp_set_scan_params *cp = data;
3788 __u16 interval, window;
3789 int err;
3790
3791 BT_DBG("%s", hdev->name);
3792
3793 if (!lmp_le_capable(hdev))
3794 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3795 MGMT_STATUS_NOT_SUPPORTED);
3796
3797 interval = __le16_to_cpu(cp->interval);
3798
3799 if (interval < 0x0004 || interval > 0x4000)
3800 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3801 MGMT_STATUS_INVALID_PARAMS);
3802
3803 window = __le16_to_cpu(cp->window);
3804
3805 if (window < 0x0004 || window > 0x4000)
3806 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3807 MGMT_STATUS_INVALID_PARAMS);
3808
Marcel Holtmann899e1072013-10-14 09:55:32 -07003809 if (window > interval)
3810 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3811 MGMT_STATUS_INVALID_PARAMS);
3812
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003813 hci_dev_lock(hdev);
3814
3815 hdev->le_scan_interval = interval;
3816 hdev->le_scan_window = window;
3817
3818 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3819
3820 hci_dev_unlock(hdev);
3821
3822 return err;
3823}
3824
Johan Hedberg33e38b32013-03-15 17:07:05 -05003825static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3826{
3827 struct pending_cmd *cmd;
3828
3829 BT_DBG("status 0x%02x", status);
3830
3831 hci_dev_lock(hdev);
3832
3833 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3834 if (!cmd)
3835 goto unlock;
3836
3837 if (status) {
3838 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3839 mgmt_status(status));
3840 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003841 struct mgmt_mode *cp = cmd->param;
3842
3843 if (cp->val)
3844 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3845 else
3846 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3847
Johan Hedberg33e38b32013-03-15 17:07:05 -05003848 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3849 new_settings(hdev, cmd->sk);
3850 }
3851
3852 mgmt_pending_remove(cmd);
3853
3854unlock:
3855 hci_dev_unlock(hdev);
3856}
3857
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003858static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003859 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003860{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003861 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003862 struct pending_cmd *cmd;
3863 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003864 int err;
3865
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003866 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003867
Johan Hedberg56f87902013-10-02 13:43:13 +03003868 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3869 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003870 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3871 MGMT_STATUS_NOT_SUPPORTED);
3872
Johan Hedberga7e80f22013-01-09 16:05:19 +02003873 if (cp->val != 0x00 && cp->val != 0x01)
3874 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3875 MGMT_STATUS_INVALID_PARAMS);
3876
Johan Hedberg5400c042012-02-21 16:40:33 +02003877 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003878 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003879 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003880
3881 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003882 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003883 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003884
3885 hci_dev_lock(hdev);
3886
Johan Hedberg05cbf292013-03-15 17:07:07 -05003887 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3888 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3889 MGMT_STATUS_BUSY);
3890 goto unlock;
3891 }
3892
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003893 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3894 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3895 hdev);
3896 goto unlock;
3897 }
3898
Johan Hedberg33e38b32013-03-15 17:07:05 -05003899 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3900 data, len);
3901 if (!cmd) {
3902 err = -ENOMEM;
3903 goto unlock;
3904 }
3905
3906 hci_req_init(&req, hdev);
3907
Johan Hedberg406d7802013-03-15 17:07:09 -05003908 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003909
3910 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003911 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003912 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003913 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003914 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003915 }
3916
Johan Hedberg33e38b32013-03-15 17:07:05 -05003917unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003918 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003919
Antti Julkuf6422ec2011-06-22 13:11:56 +03003920 return err;
3921}
3922
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003923static void set_bredr_scan(struct hci_request *req)
3924{
3925 struct hci_dev *hdev = req->hdev;
3926 u8 scan = 0;
3927
3928 /* Ensure that fast connectable is disabled. This function will
3929 * not do anything if the page scan parameters are already what
3930 * they should be.
3931 */
3932 write_fast_connectable(req, false);
3933
3934 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3935 scan |= SCAN_PAGE;
3936 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3937 scan |= SCAN_INQUIRY;
3938
3939 if (scan)
3940 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3941}
3942
Johan Hedberg0663ca22013-10-02 13:43:14 +03003943static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3944{
3945 struct pending_cmd *cmd;
3946
3947 BT_DBG("status 0x%02x", status);
3948
3949 hci_dev_lock(hdev);
3950
3951 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3952 if (!cmd)
3953 goto unlock;
3954
3955 if (status) {
3956 u8 mgmt_err = mgmt_status(status);
3957
3958 /* We need to restore the flag if related HCI commands
3959 * failed.
3960 */
3961 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3962
3963 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3964 } else {
3965 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3966 new_settings(hdev, cmd->sk);
3967 }
3968
3969 mgmt_pending_remove(cmd);
3970
3971unlock:
3972 hci_dev_unlock(hdev);
3973}
3974
3975static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3976{
3977 struct mgmt_mode *cp = data;
3978 struct pending_cmd *cmd;
3979 struct hci_request req;
3980 int err;
3981
3982 BT_DBG("request for %s", hdev->name);
3983
3984 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3985 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3986 MGMT_STATUS_NOT_SUPPORTED);
3987
3988 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3989 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3990 MGMT_STATUS_REJECTED);
3991
3992 if (cp->val != 0x00 && cp->val != 0x01)
3993 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3994 MGMT_STATUS_INVALID_PARAMS);
3995
3996 hci_dev_lock(hdev);
3997
3998 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3999 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4000 goto unlock;
4001 }
4002
4003 if (!hdev_is_powered(hdev)) {
4004 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03004005 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4006 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4007 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4008 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
4009 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
4010 }
4011
4012 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4013
4014 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
4015 if (err < 0)
4016 goto unlock;
4017
4018 err = new_settings(hdev, sk);
4019 goto unlock;
4020 }
4021
4022 /* Reject disabling when powered on */
4023 if (!cp->val) {
4024 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4025 MGMT_STATUS_REJECTED);
4026 goto unlock;
4027 }
4028
4029 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
4030 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
4031 MGMT_STATUS_BUSY);
4032 goto unlock;
4033 }
4034
4035 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
4036 if (!cmd) {
4037 err = -ENOMEM;
4038 goto unlock;
4039 }
4040
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004041 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03004042 * generates the correct flags.
4043 */
4044 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
4045
4046 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004047
4048 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4049 set_bredr_scan(&req);
4050
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004051 /* Since only the advertising data flags will change, there
4052 * is no need to update the scan response data.
4053 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004054 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03004055
Johan Hedberg0663ca22013-10-02 13:43:14 +03004056 err = hci_req_run(&req, set_bredr_complete);
4057 if (err < 0)
4058 mgmt_pending_remove(cmd);
4059
4060unlock:
4061 hci_dev_unlock(hdev);
4062 return err;
4063}
4064
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004065static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
4066 void *data, u16 len)
4067{
4068 struct mgmt_mode *cp = data;
4069 struct pending_cmd *cmd;
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004070 u8 val, status;
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004071 int err;
4072
4073 BT_DBG("request for %s", hdev->name);
4074
4075 status = mgmt_bredr_support(hdev);
4076 if (status)
4077 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4078 status);
4079
Marcel Holtmann5afeac142014-01-10 02:07:27 -08004080 if (!lmp_sc_capable(hdev) &&
4081 !test_bit(HCI_FORCE_SC, &hdev->dev_flags))
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004082 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4083 MGMT_STATUS_NOT_SUPPORTED);
4084
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004085 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004086 return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4087 MGMT_STATUS_INVALID_PARAMS);
4088
4089 hci_dev_lock(hdev);
4090
4091 if (!hdev_is_powered(hdev)) {
4092 bool changed;
4093
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004094 if (cp->val) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004095 changed = !test_and_set_bit(HCI_SC_ENABLED,
4096 &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004097 if (cp->val == 0x02)
4098 set_bit(HCI_SC_ONLY, &hdev->dev_flags);
4099 else
4100 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4101 } else {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004102 changed = test_and_clear_bit(HCI_SC_ENABLED,
4103 &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004104 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4105 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004106
4107 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4108 if (err < 0)
4109 goto failed;
4110
4111 if (changed)
4112 err = new_settings(hdev, sk);
4113
4114 goto failed;
4115 }
4116
4117 if (mgmt_pending_find(MGMT_OP_SET_SECURE_CONN, hdev)) {
4118 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
4119 MGMT_STATUS_BUSY);
4120 goto failed;
4121 }
4122
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004123 val = !!cp->val;
4124
4125 if (val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
4126 (cp->val == 0x02) == test_bit(HCI_SC_ONLY, &hdev->dev_flags)) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004127 err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
4128 goto failed;
4129 }
4130
4131 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SECURE_CONN, hdev, data, len);
4132 if (!cmd) {
4133 err = -ENOMEM;
4134 goto failed;
4135 }
4136
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004137 err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004138 if (err < 0) {
4139 mgmt_pending_remove(cmd);
4140 goto failed;
4141 }
4142
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08004143 if (cp->val == 0x02)
4144 set_bit(HCI_SC_ONLY, &hdev->dev_flags);
4145 else
4146 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
4147
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004148failed:
4149 hci_dev_unlock(hdev);
4150 return err;
4151}
4152
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004153static int set_debug_keys(struct sock *sk, struct hci_dev *hdev,
4154 void *data, u16 len)
4155{
4156 struct mgmt_mode *cp = data;
4157 bool changed;
4158 int err;
4159
4160 BT_DBG("request for %s", hdev->name);
4161
4162 if (cp->val != 0x00 && cp->val != 0x01)
4163 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEBUG_KEYS,
4164 MGMT_STATUS_INVALID_PARAMS);
4165
4166 hci_dev_lock(hdev);
4167
4168 if (cp->val)
4169 changed = !test_and_set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
4170 else
4171 changed = test_and_clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
4172
4173 err = send_settings_rsp(sk, MGMT_OP_SET_DEBUG_KEYS, hdev);
4174 if (err < 0)
4175 goto unlock;
4176
4177 if (changed)
4178 err = new_settings(hdev, sk);
4179
4180unlock:
4181 hci_dev_unlock(hdev);
4182 return err;
4183}
4184
Johan Hedberg41edf162014-02-18 10:19:35 +02004185static bool irk_is_valid(struct mgmt_irk_info *irk)
4186{
4187 switch (irk->addr.type) {
4188 case BDADDR_LE_PUBLIC:
4189 return true;
4190
4191 case BDADDR_LE_RANDOM:
4192 /* Two most significant bits shall be set */
4193 if ((irk->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4194 return false;
4195 return true;
4196 }
4197
4198 return false;
4199}
4200
4201static int load_irks(struct sock *sk, struct hci_dev *hdev, void *cp_data,
4202 u16 len)
4203{
4204 struct mgmt_cp_load_irks *cp = cp_data;
4205 u16 irk_count, expected_len;
4206 int i, err;
4207
4208 BT_DBG("request for %s", hdev->name);
4209
4210 if (!lmp_le_capable(hdev))
4211 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4212 MGMT_STATUS_NOT_SUPPORTED);
4213
4214 irk_count = __le16_to_cpu(cp->irk_count);
4215
4216 expected_len = sizeof(*cp) + irk_count * sizeof(struct mgmt_irk_info);
4217 if (expected_len != len) {
4218 BT_ERR("load_irks: expected %u bytes, got %u bytes",
4219 len, expected_len);
4220 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_IRKS,
4221 MGMT_STATUS_INVALID_PARAMS);
4222 }
4223
4224 BT_DBG("%s irk_count %u", hdev->name, irk_count);
4225
4226 for (i = 0; i < irk_count; i++) {
4227 struct mgmt_irk_info *key = &cp->irks[i];
4228
4229 if (!irk_is_valid(key))
4230 return cmd_status(sk, hdev->id,
4231 MGMT_OP_LOAD_IRKS,
4232 MGMT_STATUS_INVALID_PARAMS);
4233 }
4234
4235 hci_dev_lock(hdev);
4236
4237 hci_smp_irks_clear(hdev);
4238
4239 for (i = 0; i < irk_count; i++) {
4240 struct mgmt_irk_info *irk = &cp->irks[i];
4241 u8 addr_type;
4242
4243 if (irk->addr.type == BDADDR_LE_PUBLIC)
4244 addr_type = ADDR_LE_DEV_PUBLIC;
4245 else
4246 addr_type = ADDR_LE_DEV_RANDOM;
4247
4248 hci_add_irk(hdev, &irk->addr.bdaddr, addr_type, irk->val,
4249 BDADDR_ANY);
4250 }
4251
4252 set_bit(HCI_RPA_RESOLVING, &hdev->dev_flags);
4253
4254 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_IRKS, 0, NULL, 0);
4255
4256 hci_dev_unlock(hdev);
4257
4258 return err;
4259}
4260
Johan Hedberg3f706b72013-01-20 14:27:16 +02004261static bool ltk_is_valid(struct mgmt_ltk_info *key)
4262{
4263 if (key->master != 0x00 && key->master != 0x01)
4264 return false;
Marcel Holtmann490cb0b2014-02-16 12:59:05 -08004265
4266 switch (key->addr.type) {
4267 case BDADDR_LE_PUBLIC:
4268 return true;
4269
4270 case BDADDR_LE_RANDOM:
4271 /* Two most significant bits shall be set */
4272 if ((key->addr.bdaddr.b[5] & 0xc0) != 0xc0)
4273 return false;
4274 return true;
4275 }
4276
4277 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004278}
4279
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004280static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004281 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004282{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004283 struct mgmt_cp_load_long_term_keys *cp = cp_data;
4284 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004285 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004286
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004287 BT_DBG("request for %s", hdev->name);
4288
4289 if (!lmp_le_capable(hdev))
4290 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4291 MGMT_STATUS_NOT_SUPPORTED);
4292
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004293 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004294
4295 expected_len = sizeof(*cp) + key_count *
4296 sizeof(struct mgmt_ltk_info);
4297 if (expected_len != len) {
4298 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004299 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004300 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02004301 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004302 }
4303
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004304 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004305
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004306 for (i = 0; i < key_count; i++) {
4307 struct mgmt_ltk_info *key = &cp->keys[i];
4308
Johan Hedberg3f706b72013-01-20 14:27:16 +02004309 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004310 return cmd_status(sk, hdev->id,
4311 MGMT_OP_LOAD_LONG_TERM_KEYS,
4312 MGMT_STATUS_INVALID_PARAMS);
4313 }
4314
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004315 hci_dev_lock(hdev);
4316
4317 hci_smp_ltks_clear(hdev);
4318
4319 for (i = 0; i < key_count; i++) {
4320 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004321 u8 type, addr_type;
4322
4323 if (key->addr.type == BDADDR_LE_PUBLIC)
4324 addr_type = ADDR_LE_DEV_PUBLIC;
4325 else
4326 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004327
4328 if (key->master)
4329 type = HCI_SMP_LTK;
4330 else
4331 type = HCI_SMP_LTK_SLAVE;
4332
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004333 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Marcel Holtmannd40f3ee2014-01-31 18:42:17 -08004334 type, 0, key->type, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004335 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004336 }
4337
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004338 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4339 NULL, 0);
4340
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004341 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004342
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004343 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004344}
4345
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004346static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004347 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4348 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004349 bool var_len;
4350 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004351} mgmt_handlers[] = {
4352 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004353 { read_version, false, MGMT_READ_VERSION_SIZE },
4354 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4355 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4356 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4357 { set_powered, false, MGMT_SETTING_SIZE },
4358 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4359 { set_connectable, false, MGMT_SETTING_SIZE },
4360 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4361 { set_pairable, false, MGMT_SETTING_SIZE },
4362 { set_link_security, false, MGMT_SETTING_SIZE },
4363 { set_ssp, false, MGMT_SETTING_SIZE },
4364 { set_hs, false, MGMT_SETTING_SIZE },
4365 { set_le, false, MGMT_SETTING_SIZE },
4366 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4367 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4368 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4369 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4370 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4371 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4372 { disconnect, false, MGMT_DISCONNECT_SIZE },
4373 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4374 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4375 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4376 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4377 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4378 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4379 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4380 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4381 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4382 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4383 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4384 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
Marcel Holtmannec109112014-01-10 02:07:30 -08004385 { add_remote_oob_data, true, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
Johan Hedbergbe22b542012-03-01 22:24:41 +02004386 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4387 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4388 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4389 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4390 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4391 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004392 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004393 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004394 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004395 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004396 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08004397 { set_secure_conn, false, MGMT_SETTING_SIZE },
Marcel Holtmann4e39ac82014-01-31 11:55:22 -08004398 { set_debug_keys, false, MGMT_SETTING_SIZE },
Johan Hedberg41edf162014-02-18 10:19:35 +02004399 { },
4400 { load_irks, true, MGMT_LOAD_IRKS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004401};
4402
4403
Johan Hedberg03811012010-12-08 00:21:06 +02004404int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4405{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004406 void *buf;
4407 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004408 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004409 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004410 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004411 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004412 int err;
4413
4414 BT_DBG("got %zu bytes", msglen);
4415
4416 if (msglen < sizeof(*hdr))
4417 return -EINVAL;
4418
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004419 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004420 if (!buf)
4421 return -ENOMEM;
4422
4423 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4424 err = -EFAULT;
4425 goto done;
4426 }
4427
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004428 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004429 opcode = __le16_to_cpu(hdr->opcode);
4430 index = __le16_to_cpu(hdr->index);
4431 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004432
4433 if (len != msglen - sizeof(*hdr)) {
4434 err = -EINVAL;
4435 goto done;
4436 }
4437
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004438 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004439 hdev = hci_dev_get(index);
4440 if (!hdev) {
4441 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004442 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004443 goto done;
4444 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004445
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004446 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4447 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004448 err = cmd_status(sk, index, opcode,
4449 MGMT_STATUS_INVALID_INDEX);
4450 goto done;
4451 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004452 }
4453
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004454 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004455 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004456 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004457 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004458 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004459 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004460 }
4461
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004462 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004463 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004464 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004465 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004466 goto done;
4467 }
4468
Johan Hedbergbe22b542012-03-01 22:24:41 +02004469 handler = &mgmt_handlers[opcode];
4470
4471 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004472 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004473 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004474 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004475 goto done;
4476 }
4477
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004478 if (hdev)
4479 mgmt_init_hdev(sk, hdev);
4480
4481 cp = buf + sizeof(*hdr);
4482
Johan Hedbergbe22b542012-03-01 22:24:41 +02004483 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004484 if (err < 0)
4485 goto done;
4486
Johan Hedberg03811012010-12-08 00:21:06 +02004487 err = msglen;
4488
4489done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004490 if (hdev)
4491 hci_dev_put(hdev);
4492
Johan Hedberg03811012010-12-08 00:21:06 +02004493 kfree(buf);
4494 return err;
4495}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004496
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004497void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004498{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004499 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004500 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004501
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004502 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004503}
4504
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004505void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004506{
Johan Hedberg5f159032012-03-02 03:13:19 +02004507 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004508
Marcel Holtmann1514b892013-10-06 08:25:01 -07004509 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004510 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004511
Johan Hedberg744cf192011-11-08 20:40:14 +02004512 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004513
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004514 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004515}
4516
Johan Hedberg229ab392013-03-15 17:06:53 -05004517static void powered_complete(struct hci_dev *hdev, u8 status)
4518{
4519 struct cmd_lookup match = { NULL, hdev };
4520
4521 BT_DBG("status 0x%02x", status);
4522
4523 hci_dev_lock(hdev);
4524
4525 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4526
4527 new_settings(hdev, match.sk);
4528
4529 hci_dev_unlock(hdev);
4530
4531 if (match.sk)
4532 sock_put(match.sk);
4533}
4534
Johan Hedberg70da6242013-03-15 17:06:51 -05004535static int powered_update_hci(struct hci_dev *hdev)
4536{
Johan Hedberg890ea892013-03-15 17:06:52 -05004537 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004538 u8 link_sec;
4539
Johan Hedberg890ea892013-03-15 17:06:52 -05004540 hci_req_init(&req, hdev);
4541
Johan Hedberg70da6242013-03-15 17:06:51 -05004542 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4543 !lmp_host_ssp_capable(hdev)) {
4544 u8 ssp = 1;
4545
Johan Hedberg890ea892013-03-15 17:06:52 -05004546 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004547 }
4548
Johan Hedbergc73eee92013-04-19 18:35:21 +03004549 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4550 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004551 struct hci_cp_write_le_host_supported cp;
4552
4553 cp.le = 1;
4554 cp.simul = lmp_le_br_capable(hdev);
4555
4556 /* Check first if we already have the right
4557 * host state (host features set)
4558 */
4559 if (cp.le != lmp_host_le_capable(hdev) ||
4560 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004561 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4562 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004563 }
4564
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004565 if (lmp_le_capable(hdev)) {
4566 /* Set random address to static address if configured */
4567 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4568 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4569 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004570
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004571 /* Make sure the controller has a good default for
4572 * advertising data. This also applies to the case
4573 * where BR/EDR was toggled during the AUTO_OFF phase.
4574 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004575 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004576 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004577 update_scan_rsp_data(&req);
4578 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004579
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004580 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4581 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004582 }
4583
Johan Hedberg70da6242013-03-15 17:06:51 -05004584 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4585 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004586 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4587 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004588
4589 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004590 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4591 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004592 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004593 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004594 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004595 }
4596
Johan Hedberg229ab392013-03-15 17:06:53 -05004597 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004598}
4599
Johan Hedberg744cf192011-11-08 20:40:14 +02004600int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004601{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004602 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004603 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4604 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004605 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004606
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004607 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4608 return 0;
4609
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004610 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004611 if (powered_update_hci(hdev) == 0)
4612 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004613
Johan Hedberg229ab392013-03-15 17:06:53 -05004614 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4615 &match);
4616 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004617 }
4618
Johan Hedberg229ab392013-03-15 17:06:53 -05004619 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4620 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4621
4622 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4623 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4624 zero_cod, sizeof(zero_cod), NULL);
4625
4626new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004627 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004628
4629 if (match.sk)
4630 sock_put(match.sk);
4631
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004632 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004633}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004634
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004635void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004636{
4637 struct pending_cmd *cmd;
4638 u8 status;
4639
4640 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4641 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004642 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004643
4644 if (err == -ERFKILL)
4645 status = MGMT_STATUS_RFKILLED;
4646 else
4647 status = MGMT_STATUS_FAILED;
4648
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004649 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004650
4651 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004652}
4653
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004654void mgmt_discoverable_timeout(struct hci_dev *hdev)
4655{
4656 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004657
4658 hci_dev_lock(hdev);
4659
4660 /* When discoverable timeout triggers, then just make sure
4661 * the limited discoverable flag is cleared. Even in the case
4662 * of a timeout triggered from general discoverable, it is
4663 * safe to unconditionally clear the flag.
4664 */
4665 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004666 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004667
4668 hci_req_init(&req, hdev);
Johan Hedberg4b580612013-10-19 23:38:21 +03004669 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4670 u8 scan = SCAN_PAGE;
4671 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
4672 sizeof(scan), &scan);
4673 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004674 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004675 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004676 hci_req_run(&req, NULL);
4677
4678 hdev->discov_timeout = 0;
4679
Johan Hedberg9a43e252013-10-20 19:00:07 +03004680 new_settings(hdev, NULL);
4681
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004682 hci_dev_unlock(hdev);
4683}
4684
Marcel Holtmann86a75642013-10-15 06:33:54 -07004685void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004686{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004687 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004688
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004689 /* Nothing needed here if there's a pending command since that
4690 * commands request completion callback takes care of everything
4691 * necessary.
4692 */
4693 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004694 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004695
Johan Hedberg9a43e252013-10-20 19:00:07 +03004696 if (discoverable) {
Marcel Holtmann86a75642013-10-15 06:33:54 -07004697 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004698 } else {
4699 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmann86a75642013-10-15 06:33:54 -07004700 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004701 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004702
Johan Hedberg9a43e252013-10-20 19:00:07 +03004703 if (changed) {
4704 struct hci_request req;
4705
4706 /* In case this change in discoverable was triggered by
4707 * a disabling of connectable there could be a need to
4708 * update the advertising flags.
4709 */
4710 hci_req_init(&req, hdev);
4711 update_adv_data(&req);
4712 hci_req_run(&req, NULL);
4713
Marcel Holtmann86a75642013-10-15 06:33:54 -07004714 new_settings(hdev, NULL);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004715 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004716}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004717
Marcel Holtmanna3309162013-10-15 06:33:55 -07004718void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004719{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004720 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004721
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004722 /* Nothing needed here if there's a pending command since that
4723 * commands request completion callback takes care of everything
4724 * necessary.
4725 */
4726 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004727 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004728
Marcel Holtmanna3309162013-10-15 06:33:55 -07004729 if (connectable)
4730 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4731 else
4732 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004733
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004734 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004735 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004736}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004737
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004738void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004739{
Johan Hedbergca69b792011-11-11 18:10:00 +02004740 u8 mgmt_err = mgmt_status(status);
4741
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004742 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004743 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004744 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004745
4746 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004747 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004748 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004749}
4750
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004751void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4752 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004753{
Johan Hedberg86742e12011-11-07 23:13:38 +02004754 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004755
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004756 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004757
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004758 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004759 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004760 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004761 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004762 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004763 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004764
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004765 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004766}
Johan Hedbergf7520542011-01-20 12:34:39 +02004767
Marcel Holtmann083368f2013-10-15 14:26:29 -07004768void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004769{
4770 struct mgmt_ev_new_long_term_key ev;
4771
4772 memset(&ev, 0, sizeof(ev));
4773
4774 ev.store_hint = persistent;
4775 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004776 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Marcel Holtmannd40f3ee2014-01-31 18:42:17 -08004777 ev.key.type = key->authenticated;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004778 ev.key.enc_size = key->enc_size;
4779 ev.key.ediv = key->ediv;
4780
4781 if (key->type == HCI_SMP_LTK)
4782 ev.key.master = 1;
4783
4784 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4785 memcpy(ev.key.val, key->val, sizeof(key->val));
4786
Marcel Holtmann083368f2013-10-15 14:26:29 -07004787 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004788}
4789
Marcel Holtmann94933992013-10-15 10:26:39 -07004790static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4791 u8 data_len)
4792{
4793 eir[eir_len++] = sizeof(type) + data_len;
4794 eir[eir_len++] = type;
4795 memcpy(&eir[eir_len], data, data_len);
4796 eir_len += data_len;
4797
4798 return eir_len;
4799}
4800
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004801void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4802 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4803 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004804{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004805 char buf[512];
4806 struct mgmt_ev_device_connected *ev = (void *) buf;
4807 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004808
Johan Hedbergb644ba32012-01-17 21:48:47 +02004809 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004810 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004811
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004812 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004813
Johan Hedbergb644ba32012-01-17 21:48:47 +02004814 if (name_len > 0)
4815 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004816 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004817
4818 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004819 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004820 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004821
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004822 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004823
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004824 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4825 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004826}
4827
Johan Hedberg8962ee72011-01-20 12:40:27 +02004828static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4829{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004830 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004831 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004832 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004833
Johan Hedberg88c3df12012-02-09 14:27:38 +02004834 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4835 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004836
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004837 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004838 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004839
4840 *sk = cmd->sk;
4841 sock_hold(*sk);
4842
Johan Hedberga664b5b2011-02-19 12:06:02 -03004843 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004844}
4845
Johan Hedberg124f6e32012-02-09 13:50:12 +02004846static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004847{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004848 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004849 struct mgmt_cp_unpair_device *cp = cmd->param;
4850 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004851
4852 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004853 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4854 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004855
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004856 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4857
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004858 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004859
4860 mgmt_pending_remove(cmd);
4861}
4862
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004863void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4864 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004865{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004866 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004867 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004868
Andre Guedes57eb7762013-10-30 19:01:41 -03004869 if (link_type != ACL_LINK && link_type != LE_LINK)
4870 return;
4871
Johan Hedberg744cf192011-11-08 20:40:14 +02004872 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004873
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004874 bacpy(&ev.addr.bdaddr, bdaddr);
4875 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4876 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004877
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004878 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004879
4880 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004881 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004882
Johan Hedberg124f6e32012-02-09 13:50:12 +02004883 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004884 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004885}
4886
Marcel Holtmann78929242013-10-06 23:55:47 -07004887void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4888 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004889{
Andre Guedes3655bba2013-10-30 19:01:40 -03004890 u8 bdaddr_type = link_to_bdaddr(link_type, addr_type);
4891 struct mgmt_cp_disconnect *cp;
Johan Hedberg88c3df12012-02-09 14:27:38 +02004892 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004893 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004894
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004895 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4896 hdev);
4897
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004898 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004899 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004900 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004901
Andre Guedes3655bba2013-10-30 19:01:40 -03004902 cp = cmd->param;
4903
4904 if (bacmp(bdaddr, &cp->addr.bdaddr))
4905 return;
4906
4907 if (cp->addr.type != bdaddr_type)
4908 return;
4909
Johan Hedberg88c3df12012-02-09 14:27:38 +02004910 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes3655bba2013-10-30 19:01:40 -03004911 rp.addr.type = bdaddr_type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004912
Marcel Holtmann78929242013-10-06 23:55:47 -07004913 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4914 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004915
Johan Hedberga664b5b2011-02-19 12:06:02 -03004916 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004917}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004918
Marcel Holtmann445608d2013-10-06 23:55:48 -07004919void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4920 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004921{
4922 struct mgmt_ev_connect_failed ev;
4923
Johan Hedberg4c659c32011-11-07 23:13:39 +02004924 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004925 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004926 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004927
Marcel Holtmann445608d2013-10-06 23:55:48 -07004928 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004929}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004930
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004931void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004932{
4933 struct mgmt_ev_pin_code_request ev;
4934
Johan Hedbergd8457692012-02-17 14:24:57 +02004935 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004936 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004937 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004938
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004939 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004940}
4941
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004942void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4943 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004944{
4945 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004946 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004947
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004948 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004949 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004950 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004951
Johan Hedbergd8457692012-02-17 14:24:57 +02004952 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004953 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004954
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004955 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
4956 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004957
Johan Hedberga664b5b2011-02-19 12:06:02 -03004958 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004959}
4960
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004961void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4962 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004963{
4964 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004965 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004966
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004967 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004968 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004969 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004970
Johan Hedbergd8457692012-02-17 14:24:57 +02004971 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004972 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004973
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004974 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
4975 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004976
Johan Hedberga664b5b2011-02-19 12:06:02 -03004977 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004978}
Johan Hedberga5c29682011-02-19 12:05:57 -03004979
Johan Hedberg744cf192011-11-08 20:40:14 +02004980int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004981 u8 link_type, u8 addr_type, __le32 value,
4982 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004983{
4984 struct mgmt_ev_user_confirm_request ev;
4985
Johan Hedberg744cf192011-11-08 20:40:14 +02004986 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004987
Johan Hedberg272d90d2012-02-09 15:26:12 +02004988 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004989 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004990 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02004991 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004992
Johan Hedberg744cf192011-11-08 20:40:14 +02004993 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004994 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004995}
4996
Johan Hedberg272d90d2012-02-09 15:26:12 +02004997int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004998 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004999{
5000 struct mgmt_ev_user_passkey_request ev;
5001
5002 BT_DBG("%s", hdev->name);
5003
Johan Hedberg272d90d2012-02-09 15:26:12 +02005004 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005005 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08005006
5007 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005008 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08005009}
5010
Brian Gix0df4c182011-11-16 13:53:13 -08005011static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03005012 u8 link_type, u8 addr_type, u8 status,
5013 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03005014{
5015 struct pending_cmd *cmd;
5016 struct mgmt_rp_user_confirm_reply rp;
5017 int err;
5018
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005019 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03005020 if (!cmd)
5021 return -ENOENT;
5022
Johan Hedberg272d90d2012-02-09 15:26:12 +02005023 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005024 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02005025 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005026 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03005027
Johan Hedberga664b5b2011-02-19 12:06:02 -03005028 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03005029
5030 return err;
5031}
5032
Johan Hedberg744cf192011-11-08 20:40:14 +02005033int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005034 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03005035{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005036 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005037 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03005038}
5039
Johan Hedberg272d90d2012-02-09 15:26:12 +02005040int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005041 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03005042{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005043 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03005044 status,
5045 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03005046}
Johan Hedberg2a611692011-02-19 12:06:00 -03005047
Brian Gix604086b2011-11-23 08:28:33 -08005048int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005049 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08005050{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005051 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005052 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08005053}
5054
Johan Hedberg272d90d2012-02-09 15:26:12 +02005055int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005056 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08005057{
Johan Hedberg272d90d2012-02-09 15:26:12 +02005058 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03005059 status,
5060 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08005061}
5062
Johan Hedberg92a25252012-09-06 18:39:26 +03005063int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
5064 u8 link_type, u8 addr_type, u32 passkey,
5065 u8 entered)
5066{
5067 struct mgmt_ev_passkey_notify ev;
5068
5069 BT_DBG("%s", hdev->name);
5070
5071 bacpy(&ev.addr.bdaddr, bdaddr);
5072 ev.addr.type = link_to_bdaddr(link_type, addr_type);
5073 ev.passkey = __cpu_to_le32(passkey);
5074 ev.entered = entered;
5075
5076 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
5077}
5078
Marcel Holtmanne5460992013-10-15 14:26:23 -07005079void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5080 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03005081{
5082 struct mgmt_ev_auth_failed ev;
5083
Johan Hedbergbab73cb2012-02-09 16:07:29 +02005084 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005085 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02005086 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03005087
Marcel Holtmanne5460992013-10-15 14:26:23 -07005088 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03005089}
Johan Hedbergb312b1612011-03-16 14:29:37 +02005090
Marcel Holtmann464996a2013-10-15 14:26:24 -07005091void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005092{
5093 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07005094 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005095
5096 if (status) {
5097 u8 mgmt_err = mgmt_status(status);
5098 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005099 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07005100 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005101 }
5102
Marcel Holtmann464996a2013-10-15 14:26:24 -07005103 if (test_bit(HCI_AUTH, &hdev->flags))
5104 changed = !test_and_set_bit(HCI_LINK_SECURITY,
5105 &hdev->dev_flags);
5106 else
5107 changed = test_and_clear_bit(HCI_LINK_SECURITY,
5108 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02005109
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005110 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005111 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005112
Johan Hedberg47990ea2012-02-22 11:58:37 +02005113 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07005114 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005115
5116 if (match.sk)
5117 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02005118}
5119
Johan Hedberg890ea892013-03-15 17:06:52 -05005120static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02005121{
Johan Hedberg890ea892013-03-15 17:06:52 -05005122 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02005123 struct hci_cp_write_eir cp;
5124
Johan Hedberg976eb202012-10-24 21:12:01 +03005125 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05005126 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02005127
Johan Hedbergc80da272012-02-22 15:38:48 +02005128 memset(hdev->eir, 0, sizeof(hdev->eir));
5129
Johan Hedbergcacaf522012-02-21 00:52:42 +02005130 memset(&cp, 0, sizeof(cp));
5131
Johan Hedberg890ea892013-03-15 17:06:52 -05005132 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02005133}
5134
Marcel Holtmann3e248562013-10-15 14:26:25 -07005135void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005136{
5137 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05005138 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005139 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005140
5141 if (status) {
5142 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005143
5144 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005145 &hdev->dev_flags)) {
5146 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07005147 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005148 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005149
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005150 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
5151 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07005152 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005153 }
5154
5155 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005156 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005157 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07005158 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
5159 if (!changed)
5160 changed = test_and_clear_bit(HCI_HS_ENABLED,
5161 &hdev->dev_flags);
5162 else
5163 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005164 }
5165
5166 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
5167
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02005168 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07005169 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005170
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005171 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005172 sock_put(match.sk);
5173
Johan Hedberg890ea892013-03-15 17:06:52 -05005174 hci_req_init(&req, hdev);
5175
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005176 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05005177 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02005178 else
Johan Hedberg890ea892013-03-15 17:06:52 -05005179 clear_eir(&req);
5180
5181 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02005182}
5183
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005184void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
5185{
5186 struct cmd_lookup match = { NULL, hdev };
5187 bool changed = false;
5188
5189 if (status) {
5190 u8 mgmt_err = mgmt_status(status);
5191
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005192 if (enable) {
5193 if (test_and_clear_bit(HCI_SC_ENABLED,
5194 &hdev->dev_flags))
5195 new_settings(hdev, NULL);
5196 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
5197 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005198
5199 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5200 cmd_status_rsp, &mgmt_err);
5201 return;
5202 }
5203
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005204 if (enable) {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005205 changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005206 } else {
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005207 changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
Marcel Holtmann0ab04a92014-02-01 09:19:57 -08005208 clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
5209 }
Marcel Holtmanneac83dc2014-01-10 02:07:23 -08005210
5211 mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
5212 settings_rsp, &match);
5213
5214 if (changed)
5215 new_settings(hdev, match.sk);
5216
5217 if (match.sk)
5218 sock_put(match.sk);
5219}
5220
Johan Hedberg92da6092013-03-15 17:06:55 -05005221static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02005222{
5223 struct cmd_lookup *match = data;
5224
Johan Hedberg90e70452012-02-23 23:09:40 +02005225 if (match->sk == NULL) {
5226 match->sk = cmd->sk;
5227 sock_hold(match->sk);
5228 }
Johan Hedberg90e70452012-02-23 23:09:40 +02005229}
5230
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005231void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
5232 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005233{
Johan Hedberg90e70452012-02-23 23:09:40 +02005234 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005235
Johan Hedberg92da6092013-03-15 17:06:55 -05005236 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
5237 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
5238 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02005239
5240 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07005241 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
5242 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02005243
5244 if (match.sk)
5245 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01005246}
5247
Marcel Holtmann7667da32013-10-15 14:26:27 -07005248void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02005249{
Johan Hedbergb312b1612011-03-16 14:29:37 +02005250 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05005251 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005252
Johan Hedberg13928972013-03-15 17:07:00 -05005253 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07005254 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005255
5256 memset(&ev, 0, sizeof(ev));
5257 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02005258 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005259
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005260 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05005261 if (!cmd) {
5262 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02005263
Johan Hedberg13928972013-03-15 17:07:00 -05005264 /* If this is a HCI command related to powering on the
5265 * HCI dev don't send any mgmt signals.
5266 */
5267 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07005268 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02005269 }
5270
Marcel Holtmann7667da32013-10-15 14:26:27 -07005271 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
5272 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02005273}
Szymon Jancc35938b2011-03-22 13:12:21 +01005274
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005275void mgmt_read_local_oob_data_complete(struct hci_dev *hdev, u8 *hash192,
5276 u8 *randomizer192, u8 *hash256,
5277 u8 *randomizer256, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01005278{
5279 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01005280
Johan Hedberg744cf192011-11-08 20:40:14 +02005281 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01005282
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005283 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01005284 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005285 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01005286
5287 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07005288 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
5289 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01005290 } else {
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005291 if (test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
5292 hash256 && randomizer256) {
5293 struct mgmt_rp_read_local_oob_ext_data rp;
Szymon Jancc35938b2011-03-22 13:12:21 +01005294
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005295 memcpy(rp.hash192, hash192, sizeof(rp.hash192));
5296 memcpy(rp.randomizer192, randomizer192,
5297 sizeof(rp.randomizer192));
Szymon Jancc35938b2011-03-22 13:12:21 +01005298
Marcel Holtmann4d2d2792014-01-10 02:07:26 -08005299 memcpy(rp.hash256, hash256, sizeof(rp.hash256));
5300 memcpy(rp.randomizer256, randomizer256,
5301 sizeof(rp.randomizer256));
5302
5303 cmd_complete(cmd->sk, hdev->id,
5304 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5305 &rp, sizeof(rp));
5306 } else {
5307 struct mgmt_rp_read_local_oob_data rp;
5308
5309 memcpy(rp.hash, hash192, sizeof(rp.hash));
5310 memcpy(rp.randomizer, randomizer192,
5311 sizeof(rp.randomizer));
5312
5313 cmd_complete(cmd->sk, hdev->id,
5314 MGMT_OP_READ_LOCAL_OOB_DATA, 0,
5315 &rp, sizeof(rp));
5316 }
Szymon Jancc35938b2011-03-22 13:12:21 +01005317 }
5318
5319 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01005320}
Johan Hedberge17acd42011-03-30 23:57:16 +03005321
Marcel Holtmann901801b2013-10-06 23:55:51 -07005322void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5323 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
5324 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03005325{
Johan Hedberge319d2e2012-01-15 19:51:59 +02005326 char buf[512];
5327 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg5cedbb82014-02-18 21:41:37 +02005328 struct smp_irk *irk;
Johan Hedberg1dc06092012-01-15 21:01:23 +02005329 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03005330
Andre Guedes12602d02013-04-30 15:29:40 -03005331 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005332 return;
Andre Guedes12602d02013-04-30 15:29:40 -03005333
Johan Hedberg1dc06092012-01-15 21:01:23 +02005334 /* Leave 5 bytes for a potential CoD field */
5335 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07005336 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03005337
Johan Hedberg1dc06092012-01-15 21:01:23 +02005338 memset(buf, 0, sizeof(buf));
5339
Johan Hedberg5cedbb82014-02-18 21:41:37 +02005340 irk = hci_get_irk(hdev, bdaddr, addr_type);
5341 if (irk) {
5342 bacpy(&ev->addr.bdaddr, &irk->bdaddr);
5343 ev->addr.type = link_to_bdaddr(link_type, irk->addr_type);
5344 } else {
5345 bacpy(&ev->addr.bdaddr, bdaddr);
5346 ev->addr.type = link_to_bdaddr(link_type, addr_type);
5347 }
5348
Johan Hedberge319d2e2012-01-15 19:51:59 +02005349 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02005350 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305351 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02005352 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305353 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03005354
Johan Hedberg1dc06092012-01-15 21:01:23 +02005355 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02005356 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03005357
Johan Hedberg1dc06092012-01-15 21:01:23 +02005358 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
5359 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005360 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005361
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005362 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005363 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03005364
Marcel Holtmann901801b2013-10-06 23:55:51 -07005365 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03005366}
Johan Hedberga88a9652011-03-30 13:18:12 +03005367
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005368void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5369 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03005370{
Johan Hedbergb644ba32012-01-17 21:48:47 +02005371 struct mgmt_ev_device_found *ev;
5372 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
5373 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03005374
Johan Hedbergb644ba32012-01-17 21:48:47 +02005375 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03005376
Johan Hedbergb644ba32012-01-17 21:48:47 +02005377 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03005378
Johan Hedbergb644ba32012-01-17 21:48:47 +02005379 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005380 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005381 ev->rssi = rssi;
5382
5383 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005384 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005385
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005386 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005387
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005388 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03005389}
Johan Hedberg314b2382011-04-27 10:29:57 -04005390
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005391void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04005392{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005393 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02005394 struct pending_cmd *cmd;
5395
Andre Guedes343fb142011-11-22 17:14:19 -03005396 BT_DBG("%s discovering %u", hdev->name, discovering);
5397
Johan Hedberg164a6e72011-11-01 17:06:44 +02005398 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005399 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005400 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005401 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005402
5403 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02005404 u8 type = hdev->discovery.type;
5405
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005406 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
5407 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02005408 mgmt_pending_remove(cmd);
5409 }
5410
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005411 memset(&ev, 0, sizeof(ev));
5412 ev.type = hdev->discovery.type;
5413 ev.discovering = discovering;
5414
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005415 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04005416}
Antti Julku5e762442011-08-25 16:48:02 +03005417
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005418int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005419{
5420 struct pending_cmd *cmd;
5421 struct mgmt_ev_device_blocked ev;
5422
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005423 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005424
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005425 bacpy(&ev.addr.bdaddr, bdaddr);
5426 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005427
Johan Hedberg744cf192011-11-08 20:40:14 +02005428 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005429 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005430}
5431
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005432int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005433{
5434 struct pending_cmd *cmd;
5435 struct mgmt_ev_device_unblocked ev;
5436
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005437 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005438
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005439 bacpy(&ev.addr.bdaddr, bdaddr);
5440 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005441
Johan Hedberg744cf192011-11-08 20:40:14 +02005442 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005443 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005444}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005445
5446static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5447{
5448 BT_DBG("%s status %u", hdev->name, status);
5449
5450 /* Clear the advertising mgmt setting if we failed to re-enable it */
5451 if (status) {
5452 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005453 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005454 }
5455}
5456
5457void mgmt_reenable_advertising(struct hci_dev *hdev)
5458{
5459 struct hci_request req;
5460
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005461 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005462 return;
5463
5464 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5465 return;
5466
5467 hci_req_init(&req, hdev);
5468 enable_advertising(&req);
5469
5470 /* If this fails we have no option but to let user space know
5471 * that we've disabled advertising.
5472 */
5473 if (hci_req_run(&req, adv_enable_complete) < 0) {
5474 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005475 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005476 }
5477}