blob: bd91ee5f130ca4333765ed739e1ab51ad125f02d [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070033
34#include "smp.h"
Johan Hedberg03811012010-12-08 00:21:06 +020035
Johan Hedberg2da9c552012-02-17 14:39:28 +020036#define MGMT_VERSION 1
Marcel Holtmann9ab8cf32013-10-02 05:18:31 -070037#define MGMT_REVISION 4
Johan Hedberg02d98122010-12-13 21:07:04 +020038
Johan Hedberge70bb2e2012-02-13 16:59:33 +020039static const u16 mgmt_commands[] = {
40 MGMT_OP_READ_INDEX_LIST,
41 MGMT_OP_READ_INFO,
42 MGMT_OP_SET_POWERED,
43 MGMT_OP_SET_DISCOVERABLE,
44 MGMT_OP_SET_CONNECTABLE,
45 MGMT_OP_SET_FAST_CONNECTABLE,
46 MGMT_OP_SET_PAIRABLE,
47 MGMT_OP_SET_LINK_SECURITY,
48 MGMT_OP_SET_SSP,
49 MGMT_OP_SET_HS,
50 MGMT_OP_SET_LE,
51 MGMT_OP_SET_DEV_CLASS,
52 MGMT_OP_SET_LOCAL_NAME,
53 MGMT_OP_ADD_UUID,
54 MGMT_OP_REMOVE_UUID,
55 MGMT_OP_LOAD_LINK_KEYS,
56 MGMT_OP_LOAD_LONG_TERM_KEYS,
57 MGMT_OP_DISCONNECT,
58 MGMT_OP_GET_CONNECTIONS,
59 MGMT_OP_PIN_CODE_REPLY,
60 MGMT_OP_PIN_CODE_NEG_REPLY,
61 MGMT_OP_SET_IO_CAPABILITY,
62 MGMT_OP_PAIR_DEVICE,
63 MGMT_OP_CANCEL_PAIR_DEVICE,
64 MGMT_OP_UNPAIR_DEVICE,
65 MGMT_OP_USER_CONFIRM_REPLY,
66 MGMT_OP_USER_CONFIRM_NEG_REPLY,
67 MGMT_OP_USER_PASSKEY_REPLY,
68 MGMT_OP_USER_PASSKEY_NEG_REPLY,
69 MGMT_OP_READ_LOCAL_OOB_DATA,
70 MGMT_OP_ADD_REMOTE_OOB_DATA,
71 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
72 MGMT_OP_START_DISCOVERY,
73 MGMT_OP_STOP_DISCOVERY,
74 MGMT_OP_CONFIRM_NAME,
75 MGMT_OP_BLOCK_DEVICE,
76 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070077 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030078 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030079 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070080 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070081 MGMT_OP_SET_SCAN_PARAMS,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020082};
83
84static const u16 mgmt_events[] = {
85 MGMT_EV_CONTROLLER_ERROR,
86 MGMT_EV_INDEX_ADDED,
87 MGMT_EV_INDEX_REMOVED,
88 MGMT_EV_NEW_SETTINGS,
89 MGMT_EV_CLASS_OF_DEV_CHANGED,
90 MGMT_EV_LOCAL_NAME_CHANGED,
91 MGMT_EV_NEW_LINK_KEY,
92 MGMT_EV_NEW_LONG_TERM_KEY,
93 MGMT_EV_DEVICE_CONNECTED,
94 MGMT_EV_DEVICE_DISCONNECTED,
95 MGMT_EV_CONNECT_FAILED,
96 MGMT_EV_PIN_CODE_REQUEST,
97 MGMT_EV_USER_CONFIRM_REQUEST,
98 MGMT_EV_USER_PASSKEY_REQUEST,
99 MGMT_EV_AUTH_FAILED,
100 MGMT_EV_DEVICE_FOUND,
101 MGMT_EV_DISCOVERING,
102 MGMT_EV_DEVICE_BLOCKED,
103 MGMT_EV_DEVICE_UNBLOCKED,
104 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300105 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200106};
107
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800108#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200109
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200110#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
111 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
112
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200113struct pending_cmd {
114 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200115 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200116 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100117 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200118 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300119 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200120};
121
Johan Hedbergca69b792011-11-11 18:10:00 +0200122/* HCI to MGMT error code conversion table */
123static u8 mgmt_status_table[] = {
124 MGMT_STATUS_SUCCESS,
125 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
126 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
127 MGMT_STATUS_FAILED, /* Hardware Failure */
128 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
129 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
130 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
131 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
132 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
133 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
134 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
135 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
136 MGMT_STATUS_BUSY, /* Command Disallowed */
137 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
138 MGMT_STATUS_REJECTED, /* Rejected Security */
139 MGMT_STATUS_REJECTED, /* Rejected Personal */
140 MGMT_STATUS_TIMEOUT, /* Host Timeout */
141 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
142 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
143 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
144 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
145 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
146 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
147 MGMT_STATUS_BUSY, /* Repeated Attempts */
148 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
149 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
150 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
151 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
152 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
153 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
154 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
155 MGMT_STATUS_FAILED, /* Unspecified Error */
156 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
157 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
158 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
159 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
160 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
161 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
162 MGMT_STATUS_FAILED, /* Unit Link Key Used */
163 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
164 MGMT_STATUS_TIMEOUT, /* Instant Passed */
165 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
166 MGMT_STATUS_FAILED, /* Transaction Collision */
167 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
168 MGMT_STATUS_REJECTED, /* QoS Rejected */
169 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
170 MGMT_STATUS_REJECTED, /* Insufficient Security */
171 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
172 MGMT_STATUS_BUSY, /* Role Switch Pending */
173 MGMT_STATUS_FAILED, /* Slot Violation */
174 MGMT_STATUS_FAILED, /* Role Switch Failed */
175 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
176 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
177 MGMT_STATUS_BUSY, /* Host Busy Pairing */
178 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
179 MGMT_STATUS_BUSY, /* Controller Busy */
180 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
181 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
182 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
183 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
184 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
185};
186
187static u8 mgmt_status(u8 hci_status)
188{
189 if (hci_status < ARRAY_SIZE(mgmt_status_table))
190 return mgmt_status_table[hci_status];
191
192 return MGMT_STATUS_FAILED;
193}
194
Szymon Janc4e51eae2011-02-25 19:05:48 +0100195static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200196{
197 struct sk_buff *skb;
198 struct mgmt_hdr *hdr;
199 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300200 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200201
Szymon Janc34eb5252011-02-28 14:10:08 +0100202 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200203
Andre Guedes790eff42012-06-07 19:05:46 -0300204 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200205 if (!skb)
206 return -ENOMEM;
207
208 hdr = (void *) skb_put(skb, sizeof(*hdr));
209
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530210 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100211 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200212 hdr->len = cpu_to_le16(sizeof(*ev));
213
214 ev = (void *) skb_put(skb, sizeof(*ev));
215 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200216 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200217
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300218 err = sock_queue_rcv_skb(sk, skb);
219 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200220 kfree_skb(skb);
221
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300222 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223}
224
Johan Hedbergaee9b212012-02-18 15:07:59 +0200225static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300226 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200227{
228 struct sk_buff *skb;
229 struct mgmt_hdr *hdr;
230 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300231 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200232
233 BT_DBG("sock %p", sk);
234
Andre Guedes790eff42012-06-07 19:05:46 -0300235 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200236 if (!skb)
237 return -ENOMEM;
238
239 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200240
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530241 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100242 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200243 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200244
Johan Hedberga38528f2011-01-22 06:46:43 +0200245 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200246 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200247 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100248
249 if (rp)
250 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200251
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300252 err = sock_queue_rcv_skb(sk, skb);
253 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200254 kfree_skb(skb);
255
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100256 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200257}
258
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300259static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
260 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200261{
262 struct mgmt_rp_read_version rp;
263
264 BT_DBG("sock %p", sk);
265
266 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200267 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200268
Johan Hedbergaee9b212012-02-18 15:07:59 +0200269 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300270 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200271}
272
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300273static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
274 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200275{
276 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200277 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
278 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200279 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200280 size_t rp_size;
281 int i, err;
282
283 BT_DBG("sock %p", sk);
284
285 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
286
287 rp = kmalloc(rp_size, GFP_KERNEL);
288 if (!rp)
289 return -ENOMEM;
290
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200291 rp->num_commands = __constant_cpu_to_le16(num_commands);
292 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200293
294 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
295 put_unaligned_le16(mgmt_commands[i], opcode);
296
297 for (i = 0; i < num_events; i++, opcode++)
298 put_unaligned_le16(mgmt_events[i], opcode);
299
Johan Hedbergaee9b212012-02-18 15:07:59 +0200300 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300301 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200302 kfree(rp);
303
304 return err;
305}
306
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300307static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
308 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200309{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200310 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200311 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200312 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300314 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200315
316 BT_DBG("sock %p", sk);
317
318 read_lock(&hci_dev_list_lock);
319
320 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300321 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700322 if (d->dev_type == HCI_BREDR)
323 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324 }
325
Johan Hedberga38528f2011-01-22 06:46:43 +0200326 rp_len = sizeof(*rp) + (2 * count);
327 rp = kmalloc(rp_len, GFP_ATOMIC);
328 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100329 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200330 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100331 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200332
Johan Hedberg476e44c2012-10-19 20:10:46 +0300333 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200334 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200335 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200336 continue;
337
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700338 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
339 continue;
340
Marcel Holtmann1514b892013-10-06 08:25:01 -0700341 if (d->dev_type == HCI_BREDR) {
342 rp->index[count++] = cpu_to_le16(d->id);
343 BT_DBG("Added hci%u", d->id);
344 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200345 }
346
Johan Hedberg476e44c2012-10-19 20:10:46 +0300347 rp->num_controllers = cpu_to_le16(count);
348 rp_len = sizeof(*rp) + (2 * count);
349
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200350 read_unlock(&hci_dev_list_lock);
351
Johan Hedbergaee9b212012-02-18 15:07:59 +0200352 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300353 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354
Johan Hedberga38528f2011-01-22 06:46:43 +0200355 kfree(rp);
356
357 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200358}
359
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200360static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200361{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200363
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200366
Andre Guedesed3fa312012-07-24 15:03:46 -0300367 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300368 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500369 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
370 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300371 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 settings |= MGMT_SETTING_BREDR;
373 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700374
375 if (lmp_ssp_capable(hdev)) {
376 settings |= MGMT_SETTING_SSP;
377 settings |= MGMT_SETTING_HS;
378 }
Marcel Holtmann848566b2013-10-01 22:59:22 -0700379 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300381 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200382 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300383 settings |= MGMT_SETTING_ADVERTISING;
384 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200385
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200386 return settings;
387}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200388
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200389static u32 get_current_settings(struct hci_dev *hdev)
390{
391 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200392
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200393 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100394 settings |= MGMT_SETTING_POWERED;
395
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200396 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200397 settings |= MGMT_SETTING_CONNECTABLE;
398
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500399 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
400 settings |= MGMT_SETTING_FAST_CONNECTABLE;
401
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200402 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403 settings |= MGMT_SETTING_DISCOVERABLE;
404
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200405 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200406 settings |= MGMT_SETTING_PAIRABLE;
407
Johan Hedberg56f87902013-10-02 13:43:13 +0300408 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200409 settings |= MGMT_SETTING_BREDR;
410
Johan Hedberg06199cf2012-02-22 16:37:11 +0200411 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200412 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200413
Johan Hedberg47990ea2012-02-22 11:58:37 +0200414 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200416
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200417 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200418 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200419
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200420 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
421 settings |= MGMT_SETTING_HS;
422
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200423 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300424 settings |= MGMT_SETTING_ADVERTISING;
425
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200426 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200427}
428
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300429#define PNP_INFO_SVCLASS_ID 0x1200
430
Johan Hedberg213202e2013-01-27 00:31:33 +0200431static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
432{
433 u8 *ptr = data, *uuids_start = NULL;
434 struct bt_uuid *uuid;
435
436 if (len < 4)
437 return ptr;
438
439 list_for_each_entry(uuid, &hdev->uuids, list) {
440 u16 uuid16;
441
442 if (uuid->size != 16)
443 continue;
444
445 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
446 if (uuid16 < 0x1100)
447 continue;
448
449 if (uuid16 == PNP_INFO_SVCLASS_ID)
450 continue;
451
452 if (!uuids_start) {
453 uuids_start = ptr;
454 uuids_start[0] = 1;
455 uuids_start[1] = EIR_UUID16_ALL;
456 ptr += 2;
457 }
458
459 /* Stop if not enough space to put next UUID */
460 if ((ptr - data) + sizeof(u16) > len) {
461 uuids_start[1] = EIR_UUID16_SOME;
462 break;
463 }
464
465 *ptr++ = (uuid16 & 0x00ff);
466 *ptr++ = (uuid16 & 0xff00) >> 8;
467 uuids_start[0] += sizeof(uuid16);
468 }
469
470 return ptr;
471}
472
Johan Hedbergcdf19632013-01-27 00:31:34 +0200473static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
474{
475 u8 *ptr = data, *uuids_start = NULL;
476 struct bt_uuid *uuid;
477
478 if (len < 6)
479 return ptr;
480
481 list_for_each_entry(uuid, &hdev->uuids, list) {
482 if (uuid->size != 32)
483 continue;
484
485 if (!uuids_start) {
486 uuids_start = ptr;
487 uuids_start[0] = 1;
488 uuids_start[1] = EIR_UUID32_ALL;
489 ptr += 2;
490 }
491
492 /* Stop if not enough space to put next UUID */
493 if ((ptr - data) + sizeof(u32) > len) {
494 uuids_start[1] = EIR_UUID32_SOME;
495 break;
496 }
497
498 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
499 ptr += sizeof(u32);
500 uuids_start[0] += sizeof(u32);
501 }
502
503 return ptr;
504}
505
Johan Hedbergc00d5752013-01-27 00:31:35 +0200506static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
507{
508 u8 *ptr = data, *uuids_start = NULL;
509 struct bt_uuid *uuid;
510
511 if (len < 18)
512 return ptr;
513
514 list_for_each_entry(uuid, &hdev->uuids, list) {
515 if (uuid->size != 128)
516 continue;
517
518 if (!uuids_start) {
519 uuids_start = ptr;
520 uuids_start[0] = 1;
521 uuids_start[1] = EIR_UUID128_ALL;
522 ptr += 2;
523 }
524
525 /* Stop if not enough space to put next UUID */
526 if ((ptr - data) + 16 > len) {
527 uuids_start[1] = EIR_UUID128_SOME;
528 break;
529 }
530
531 memcpy(ptr, uuid->uuid, 16);
532 ptr += 16;
533 uuids_start[0] += 16;
534 }
535
536 return ptr;
537}
538
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300539static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
540{
541 struct pending_cmd *cmd;
542
543 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
544 if (cmd->opcode == opcode)
545 return cmd;
546 }
547
548 return NULL;
549}
550
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700551static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
552{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700553 u8 ad_len = 0;
554 size_t name_len;
555
556 name_len = strlen(hdev->dev_name);
557 if (name_len > 0) {
558 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
559
560 if (name_len > max_len) {
561 name_len = max_len;
562 ptr[1] = EIR_NAME_SHORT;
563 } else
564 ptr[1] = EIR_NAME_COMPLETE;
565
566 ptr[0] = name_len + 1;
567
568 memcpy(ptr + 2, hdev->dev_name, name_len);
569
570 ad_len += (name_len + 2);
571 ptr += (name_len + 2);
572 }
573
574 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700575}
576
577static void update_scan_rsp_data(struct hci_request *req)
578{
579 struct hci_dev *hdev = req->hdev;
580 struct hci_cp_le_set_scan_rsp_data cp;
581 u8 len;
582
Johan Hedberg7751ef12013-10-19 23:38:15 +0300583 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700584 return;
585
586 memset(&cp, 0, sizeof(cp));
587
588 len = create_scan_rsp_data(hdev, cp.data);
589
Johan Hedbergeb438b52013-10-16 15:31:07 +0300590 if (hdev->scan_rsp_data_len == len &&
591 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700592 return;
593
Johan Hedbergeb438b52013-10-16 15:31:07 +0300594 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
595 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700596
597 cp.length = len;
598
599 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
600}
601
Johan Hedberg9a43e252013-10-20 19:00:07 +0300602static u8 get_adv_discov_flags(struct hci_dev *hdev)
603{
604 struct pending_cmd *cmd;
605
606 /* If there's a pending mgmt command the flags will not yet have
607 * their final values, so check for this first.
608 */
609 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
610 if (cmd) {
611 struct mgmt_mode *cp = cmd->param;
612 if (cp->val == 0x01)
613 return LE_AD_GENERAL;
614 else if (cp->val == 0x02)
615 return LE_AD_LIMITED;
616 } else {
617 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
618 return LE_AD_LIMITED;
619 else if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
620 return LE_AD_GENERAL;
621 }
622
623 return 0;
624}
625
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700626static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700627{
628 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700629
Johan Hedberg9a43e252013-10-20 19:00:07 +0300630 flags |= get_adv_discov_flags(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700631
632 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
633 if (lmp_le_br_capable(hdev))
634 flags |= LE_AD_SIM_LE_BREDR_CTRL;
635 if (lmp_host_le_br_capable(hdev))
636 flags |= LE_AD_SIM_LE_BREDR_HOST;
637 } else {
638 flags |= LE_AD_NO_BREDR;
639 }
640
641 if (flags) {
642 BT_DBG("adv flags 0x%02x", flags);
643
644 ptr[0] = 2;
645 ptr[1] = EIR_FLAGS;
646 ptr[2] = flags;
647
648 ad_len += 3;
649 ptr += 3;
650 }
651
652 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
653 ptr[0] = 2;
654 ptr[1] = EIR_TX_POWER;
655 ptr[2] = (u8) hdev->adv_tx_power;
656
657 ad_len += 3;
658 ptr += 3;
659 }
660
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700661 return ad_len;
662}
663
Marcel Holtmann5947f4b2013-10-16 00:16:50 -0700664static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700665{
666 struct hci_dev *hdev = req->hdev;
667 struct hci_cp_le_set_adv_data cp;
668 u8 len;
669
Johan Hedberg10994ce2013-10-19 23:38:16 +0300670 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700671 return;
672
673 memset(&cp, 0, sizeof(cp));
674
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700675 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700676
677 if (hdev->adv_data_len == len &&
678 memcmp(cp.data, hdev->adv_data, len) == 0)
679 return;
680
681 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
682 hdev->adv_data_len = len;
683
684 cp.length = len;
685
686 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
687}
688
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300689static void create_eir(struct hci_dev *hdev, u8 *data)
690{
691 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300692 size_t name_len;
693
694 name_len = strlen(hdev->dev_name);
695
696 if (name_len > 0) {
697 /* EIR Data type */
698 if (name_len > 48) {
699 name_len = 48;
700 ptr[1] = EIR_NAME_SHORT;
701 } else
702 ptr[1] = EIR_NAME_COMPLETE;
703
704 /* EIR Data length */
705 ptr[0] = name_len + 1;
706
707 memcpy(ptr + 2, hdev->dev_name, name_len);
708
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300709 ptr += (name_len + 2);
710 }
711
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100712 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700713 ptr[0] = 2;
714 ptr[1] = EIR_TX_POWER;
715 ptr[2] = (u8) hdev->inq_tx_power;
716
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700717 ptr += 3;
718 }
719
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700720 if (hdev->devid_source > 0) {
721 ptr[0] = 9;
722 ptr[1] = EIR_DEVICE_ID;
723
724 put_unaligned_le16(hdev->devid_source, ptr + 2);
725 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
726 put_unaligned_le16(hdev->devid_product, ptr + 6);
727 put_unaligned_le16(hdev->devid_version, ptr + 8);
728
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700729 ptr += 10;
730 }
731
Johan Hedberg213202e2013-01-27 00:31:33 +0200732 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200733 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200734 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300735}
736
Johan Hedberg890ea892013-03-15 17:06:52 -0500737static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300738{
Johan Hedberg890ea892013-03-15 17:06:52 -0500739 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300740 struct hci_cp_write_eir cp;
741
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200742 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500743 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200744
Johan Hedberg976eb202012-10-24 21:12:01 +0300745 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500746 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300747
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200748 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500749 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300750
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200751 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500752 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300753
754 memset(&cp, 0, sizeof(cp));
755
756 create_eir(hdev, cp.data);
757
758 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500759 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300760
761 memcpy(hdev->eir, cp.data, sizeof(cp.data));
762
Johan Hedberg890ea892013-03-15 17:06:52 -0500763 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300764}
765
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200766static u8 get_service_classes(struct hci_dev *hdev)
767{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300768 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200769 u8 val = 0;
770
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300771 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200772 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200773
774 return val;
775}
776
Johan Hedberg890ea892013-03-15 17:06:52 -0500777static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200778{
Johan Hedberg890ea892013-03-15 17:06:52 -0500779 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200780 u8 cod[3];
781
782 BT_DBG("%s", hdev->name);
783
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200784 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500785 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200786
Johan Hedbergf87ea1d2013-10-19 23:38:17 +0300787 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
788 return;
789
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200790 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500791 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200792
793 cod[0] = hdev->minor_class;
794 cod[1] = hdev->major_class;
795 cod[2] = get_service_classes(hdev);
796
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700797 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
798 cod[1] |= 0x20;
799
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200800 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500801 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200802
Johan Hedberg890ea892013-03-15 17:06:52 -0500803 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200804}
805
Johan Hedberg7d785252011-12-15 00:47:39 +0200806static void service_cache_off(struct work_struct *work)
807{
808 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300809 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500810 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200811
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200812 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200813 return;
814
Johan Hedberg890ea892013-03-15 17:06:52 -0500815 hci_req_init(&req, hdev);
816
Johan Hedberg7d785252011-12-15 00:47:39 +0200817 hci_dev_lock(hdev);
818
Johan Hedberg890ea892013-03-15 17:06:52 -0500819 update_eir(&req);
820 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200821
822 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500823
824 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200825}
826
Johan Hedberg6a919082012-02-28 06:17:26 +0200827static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200828{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200829 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200830 return;
831
Johan Hedberg4f87da82012-03-02 19:55:56 +0200832 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200833
Johan Hedberg4f87da82012-03-02 19:55:56 +0200834 /* Non-mgmt controlled devices get this bit set
835 * implicitly so that pairing works for them, however
836 * for mgmt we require user-space to explicitly enable
837 * it
838 */
839 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200840}
841
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200842static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300843 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200844{
845 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200846
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200847 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200848
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300849 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200850
Johan Hedberg03811012010-12-08 00:21:06 +0200851 memset(&rp, 0, sizeof(rp));
852
Johan Hedberg03811012010-12-08 00:21:06 +0200853 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200854
855 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200856 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200857
858 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
859 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
860
861 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200862
863 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200864 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200865
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300866 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200867
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200868 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300869 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200870}
871
872static void mgmt_pending_free(struct pending_cmd *cmd)
873{
874 sock_put(cmd->sk);
875 kfree(cmd->param);
876 kfree(cmd);
877}
878
879static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300880 struct hci_dev *hdev, void *data,
881 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200882{
883 struct pending_cmd *cmd;
884
Andre Guedes12b94562012-06-07 19:05:45 -0300885 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200886 if (!cmd)
887 return NULL;
888
889 cmd->opcode = opcode;
890 cmd->index = hdev->id;
891
Andre Guedes12b94562012-06-07 19:05:45 -0300892 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200893 if (!cmd->param) {
894 kfree(cmd);
895 return NULL;
896 }
897
898 if (data)
899 memcpy(cmd->param, data, len);
900
901 cmd->sk = sk;
902 sock_hold(sk);
903
904 list_add(&cmd->list, &hdev->mgmt_pending);
905
906 return cmd;
907}
908
909static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300910 void (*cb)(struct pending_cmd *cmd,
911 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300912 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200913{
Andre Guedesa3d09352013-02-01 11:21:30 -0300914 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200915
Andre Guedesa3d09352013-02-01 11:21:30 -0300916 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200917 if (opcode > 0 && cmd->opcode != opcode)
918 continue;
919
920 cb(cmd, data);
921 }
922}
923
Johan Hedberg03811012010-12-08 00:21:06 +0200924static void mgmt_pending_remove(struct pending_cmd *cmd)
925{
926 list_del(&cmd->list);
927 mgmt_pending_free(cmd);
928}
929
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200930static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200931{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200932 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200933
Johan Hedbergaee9b212012-02-18 15:07:59 +0200934 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300935 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200936}
937
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200938static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300939 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200940{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300941 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200942 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200943 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200944
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200945 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200946
Johan Hedberga7e80f22013-01-09 16:05:19 +0200947 if (cp->val != 0x00 && cp->val != 0x01)
948 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
949 MGMT_STATUS_INVALID_PARAMS);
950
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300951 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200952
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300953 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
954 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
955 MGMT_STATUS_BUSY);
956 goto failed;
957 }
958
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100959 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
960 cancel_delayed_work(&hdev->power_off);
961
962 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200963 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
964 data, len);
965 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100966 goto failed;
967 }
968 }
969
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200970 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200971 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200972 goto failed;
973 }
974
Johan Hedberg03811012010-12-08 00:21:06 +0200975 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
976 if (!cmd) {
977 err = -ENOMEM;
978 goto failed;
979 }
980
981 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200982 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200983 else
Johan Hedberg19202572013-01-14 22:33:51 +0200984 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200985
986 err = 0;
987
988failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300989 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200990 return err;
991}
992
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300993static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
994 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200995{
996 struct sk_buff *skb;
997 struct mgmt_hdr *hdr;
998
Andre Guedes790eff42012-06-07 19:05:46 -0300999 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001000 if (!skb)
1001 return -ENOMEM;
1002
1003 hdr = (void *) skb_put(skb, sizeof(*hdr));
1004 hdr->opcode = cpu_to_le16(event);
1005 if (hdev)
1006 hdr->index = cpu_to_le16(hdev->id);
1007 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05301008 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001009 hdr->len = cpu_to_le16(data_len);
1010
1011 if (data)
1012 memcpy(skb_put(skb, data_len), data, data_len);
1013
Marcel Holtmann97e0bde2012-02-22 13:49:28 +01001014 /* Time stamp */
1015 __net_timestamp(skb);
1016
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001017 hci_send_to_control(skb, skip_sk);
1018 kfree_skb(skb);
1019
1020 return 0;
1021}
1022
1023static int new_settings(struct hci_dev *hdev, struct sock *skip)
1024{
1025 __le32 ev;
1026
1027 ev = cpu_to_le32(get_current_settings(hdev));
1028
1029 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1030}
1031
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001032struct cmd_lookup {
1033 struct sock *sk;
1034 struct hci_dev *hdev;
1035 u8 mgmt_status;
1036};
1037
1038static void settings_rsp(struct pending_cmd *cmd, void *data)
1039{
1040 struct cmd_lookup *match = data;
1041
1042 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1043
1044 list_del(&cmd->list);
1045
1046 if (match->sk == NULL) {
1047 match->sk = cmd->sk;
1048 sock_hold(match->sk);
1049 }
1050
1051 mgmt_pending_free(cmd);
1052}
1053
1054static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1055{
1056 u8 *status = data;
1057
1058 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1059 mgmt_pending_remove(cmd);
1060}
1061
Johan Hedberge6fe7982013-10-02 15:45:22 +03001062static u8 mgmt_bredr_support(struct hci_dev *hdev)
1063{
1064 if (!lmp_bredr_capable(hdev))
1065 return MGMT_STATUS_NOT_SUPPORTED;
1066 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1067 return MGMT_STATUS_REJECTED;
1068 else
1069 return MGMT_STATUS_SUCCESS;
1070}
1071
1072static u8 mgmt_le_support(struct hci_dev *hdev)
1073{
1074 if (!lmp_le_capable(hdev))
1075 return MGMT_STATUS_NOT_SUPPORTED;
1076 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1077 return MGMT_STATUS_REJECTED;
1078 else
1079 return MGMT_STATUS_SUCCESS;
1080}
1081
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001082static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1083{
1084 struct pending_cmd *cmd;
1085 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001086 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001087 bool changed;
1088
1089 BT_DBG("status 0x%02x", status);
1090
1091 hci_dev_lock(hdev);
1092
1093 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1094 if (!cmd)
1095 goto unlock;
1096
1097 if (status) {
1098 u8 mgmt_err = mgmt_status(status);
1099 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001100 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001101 goto remove_cmd;
1102 }
1103
1104 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001105 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001106 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1107 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001108
1109 if (hdev->discov_timeout > 0) {
1110 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1111 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1112 to);
1113 }
1114 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001115 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1116 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001117 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001118
1119 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1120
1121 if (changed)
1122 new_settings(hdev, cmd->sk);
1123
Marcel Holtmann970ba522013-10-15 06:33:57 -07001124 /* When the discoverable mode gets changed, make sure
1125 * that class of device has the limited discoverable
1126 * bit correctly set.
1127 */
1128 hci_req_init(&req, hdev);
1129 update_class(&req);
1130 hci_req_run(&req, NULL);
1131
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001132remove_cmd:
1133 mgmt_pending_remove(cmd);
1134
1135unlock:
1136 hci_dev_unlock(hdev);
1137}
1138
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001139static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001140 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001141{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001142 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001143 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001144 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001145 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001146 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001147 int err;
1148
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001149 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001150
Johan Hedberg9a43e252013-10-20 19:00:07 +03001151 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1152 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001153 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberg9a43e252013-10-20 19:00:07 +03001154 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001155
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001156 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga7e80f22013-01-09 16:05:19 +02001157 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1158 MGMT_STATUS_INVALID_PARAMS);
1159
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001160 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001161
1162 /* Disabling discoverable requires that no timeout is set,
1163 * and enabling limited discoverable requires a timeout.
1164 */
1165 if ((cp->val == 0x00 && timeout > 0) ||
1166 (cp->val == 0x02 && timeout == 0))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001167 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001168 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001169
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001170 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001171
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001172 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001173 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001174 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001175 goto failed;
1176 }
1177
1178 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001179 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001180 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001181 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001182 goto failed;
1183 }
1184
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001185 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001186 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001187 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001188 goto failed;
1189 }
1190
1191 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001192 bool changed = false;
1193
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001194 /* Setting limited discoverable when powered off is
1195 * not a valid operation since it requires a timeout
1196 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1197 */
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001198 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1199 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1200 changed = true;
1201 }
1202
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001203 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001204 if (err < 0)
1205 goto failed;
1206
1207 if (changed)
1208 err = new_settings(hdev, sk);
1209
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001210 goto failed;
1211 }
1212
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001213 /* If the current mode is the same, then just update the timeout
1214 * value with the new value. And if only the timeout gets updated,
1215 * then no need for any HCI transactions.
1216 */
1217 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) &&
1218 (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE,
1219 &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001220 cancel_delayed_work(&hdev->discov_off);
1221 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001222
Marcel Holtmann36261542013-10-15 08:28:51 -07001223 if (cp->val && hdev->discov_timeout > 0) {
1224 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001225 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001226 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001227 }
1228
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001229 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001230 goto failed;
1231 }
1232
1233 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1234 if (!cmd) {
1235 err = -ENOMEM;
1236 goto failed;
1237 }
1238
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001239 /* Cancel any potential discoverable timeout that might be
1240 * still active and store new timeout value. The arming of
1241 * the timeout happens in the complete handler.
1242 */
1243 cancel_delayed_work(&hdev->discov_off);
1244 hdev->discov_timeout = timeout;
1245
Johan Hedbergb456f872013-10-19 23:38:22 +03001246 /* Limited discoverable mode */
1247 if (cp->val == 0x02)
1248 set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1249 else
1250 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1251
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001252 hci_req_init(&req, hdev);
1253
Johan Hedberg9a43e252013-10-20 19:00:07 +03001254 /* The procedure for LE-only controllers is much simpler - just
1255 * update the advertising data.
1256 */
1257 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1258 goto update_ad;
1259
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001260 scan = SCAN_PAGE;
1261
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001262 if (cp->val) {
1263 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001264
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001265 if (cp->val == 0x02) {
1266 /* Limited discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001267 hci_cp.num_iac = 2;
1268 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1269 hci_cp.iac_lap[1] = 0x8b;
1270 hci_cp.iac_lap[2] = 0x9e;
1271 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1272 hci_cp.iac_lap[4] = 0x8b;
1273 hci_cp.iac_lap[5] = 0x9e;
1274 } else {
1275 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001276 hci_cp.num_iac = 1;
1277 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1278 hci_cp.iac_lap[1] = 0x8b;
1279 hci_cp.iac_lap[2] = 0x9e;
1280 }
1281
1282 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1283 (hci_cp.num_iac * 3) + 1, &hci_cp);
1284
1285 scan |= SCAN_INQUIRY;
1286 } else {
1287 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1288 }
1289
1290 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001291
Johan Hedberg9a43e252013-10-20 19:00:07 +03001292update_ad:
1293 update_adv_data(&req);
1294
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001295 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001296 if (err < 0)
1297 mgmt_pending_remove(cmd);
1298
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001299failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001300 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001301 return err;
1302}
1303
Johan Hedberg406d7802013-03-15 17:07:09 -05001304static void write_fast_connectable(struct hci_request *req, bool enable)
1305{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001306 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001307 struct hci_cp_write_page_scan_activity acp;
1308 u8 type;
1309
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001310 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1311 return;
1312
Johan Hedberg406d7802013-03-15 17:07:09 -05001313 if (enable) {
1314 type = PAGE_SCAN_TYPE_INTERLACED;
1315
1316 /* 160 msec page scan interval */
1317 acp.interval = __constant_cpu_to_le16(0x0100);
1318 } else {
1319 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1320
1321 /* default 1.28 sec page scan */
1322 acp.interval = __constant_cpu_to_le16(0x0800);
1323 }
1324
1325 acp.window = __constant_cpu_to_le16(0x0012);
1326
Johan Hedbergbd98b992013-03-15 17:07:13 -05001327 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1328 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1329 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1330 sizeof(acp), &acp);
1331
1332 if (hdev->page_scan_type != type)
1333 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001334}
1335
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001336static u8 get_adv_type(struct hci_dev *hdev)
1337{
1338 struct pending_cmd *cmd;
1339 bool connectable;
1340
1341 /* If there's a pending mgmt command the flag will not yet have
1342 * it's final value, so check for this first.
1343 */
1344 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1345 if (cmd) {
1346 struct mgmt_mode *cp = cmd->param;
1347 connectable = !!cp->val;
1348 } else {
1349 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1350 }
1351
1352 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1353}
1354
Johan Hedberg95c66e72013-10-14 16:20:06 +03001355static void enable_advertising(struct hci_request *req)
1356{
1357 struct hci_dev *hdev = req->hdev;
1358 struct hci_cp_le_set_adv_param cp;
1359 u8 enable = 0x01;
1360
1361 memset(&cp, 0, sizeof(cp));
1362 cp.min_interval = __constant_cpu_to_le16(0x0800);
1363 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001364 cp.type = get_adv_type(hdev);
Marcel Holtmann79830f62013-10-18 16:38:09 -07001365 cp.own_address_type = hdev->own_addr_type;
Johan Hedberg95c66e72013-10-14 16:20:06 +03001366 cp.channel_map = 0x07;
1367
1368 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1369
1370 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1371}
1372
1373static void disable_advertising(struct hci_request *req)
1374{
1375 u8 enable = 0x00;
1376
1377 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1378}
1379
Johan Hedberg2b76f452013-03-15 17:07:04 -05001380static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1381{
1382 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001383 struct mgmt_mode *cp;
1384 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001385
1386 BT_DBG("status 0x%02x", status);
1387
1388 hci_dev_lock(hdev);
1389
1390 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1391 if (!cmd)
1392 goto unlock;
1393
Johan Hedberg37438c12013-10-14 16:20:05 +03001394 if (status) {
1395 u8 mgmt_err = mgmt_status(status);
1396 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1397 goto remove_cmd;
1398 }
1399
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001400 cp = cmd->param;
1401 if (cp->val)
1402 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1403 else
1404 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1405
Johan Hedberg2b76f452013-03-15 17:07:04 -05001406 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1407
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001408 if (changed)
1409 new_settings(hdev, cmd->sk);
1410
Johan Hedberg37438c12013-10-14 16:20:05 +03001411remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001412 mgmt_pending_remove(cmd);
1413
1414unlock:
1415 hci_dev_unlock(hdev);
1416}
1417
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001418static int set_connectable_update_settings(struct hci_dev *hdev,
1419 struct sock *sk, u8 val)
1420{
1421 bool changed = false;
1422 int err;
1423
1424 if (!!val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1425 changed = true;
1426
1427 if (val) {
1428 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1429 } else {
1430 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1431 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1432 }
1433
1434 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1435 if (err < 0)
1436 return err;
1437
1438 if (changed)
1439 return new_settings(hdev, sk);
1440
1441 return 0;
1442}
1443
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001444static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001445 u16 len)
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001446{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001447 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001448 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001449 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001450 u8 scan;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001451 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001452
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001453 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001454
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001455 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1456 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001457 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001458 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001459
Johan Hedberga7e80f22013-01-09 16:05:19 +02001460 if (cp->val != 0x00 && cp->val != 0x01)
1461 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1462 MGMT_STATUS_INVALID_PARAMS);
1463
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001464 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001465
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001466 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a1f2013-10-19 23:38:18 +03001467 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001468 goto failed;
1469 }
1470
1471 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001472 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001473 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001474 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001475 goto failed;
1476 }
1477
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001478 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1479 if (!cmd) {
1480 err = -ENOMEM;
1481 goto failed;
1482 }
1483
Johan Hedberg2b76f452013-03-15 17:07:04 -05001484 hci_req_init(&req, hdev);
1485
Johan Hedberg9a43e252013-10-20 19:00:07 +03001486 /* If BR/EDR is not enabled and we disable advertising as a
1487 * by-product of disabling connectable, we need to update the
1488 * advertising flags.
1489 */
1490 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
1491 if (!cp->val) {
1492 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1493 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1494 }
1495 update_adv_data(&req);
1496 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001497 if (cp->val) {
1498 scan = SCAN_PAGE;
1499 } else {
1500 scan = 0;
1501
1502 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001503 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001504 cancel_delayed_work(&hdev->discov_off);
1505 }
1506
1507 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1508 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001509
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001510 /* If we're going from non-connectable to connectable or
1511 * vice-versa when fast connectable is enabled ensure that fast
1512 * connectable gets disabled. write_fast_connectable won't do
1513 * anything if the page scan parameters are already what they
1514 * should be.
1515 */
1516 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001517 write_fast_connectable(&req, false);
1518
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001519 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1520 hci_conn_num(hdev, LE_LINK) == 0) {
1521 disable_advertising(&req);
1522 enable_advertising(&req);
1523 }
1524
Johan Hedberg2b76f452013-03-15 17:07:04 -05001525 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001526 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001527 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001528 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03001529 err = set_connectable_update_settings(hdev, sk,
1530 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03001531 goto failed;
1532 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001533
1534failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001535 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001536 return err;
1537}
1538
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001539static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001540 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001541{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001542 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001543 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001544 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001545
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001546 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001547
Johan Hedberga7e80f22013-01-09 16:05:19 +02001548 if (cp->val != 0x00 && cp->val != 0x01)
1549 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1550 MGMT_STATUS_INVALID_PARAMS);
1551
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001552 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001553
1554 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001555 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001556 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001557 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001558
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001559 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001560 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001561 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001562
Marcel Holtmann55594352013-10-06 16:11:57 -07001563 if (changed)
1564 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001565
Marcel Holtmann55594352013-10-06 16:11:57 -07001566unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001567 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001568 return err;
1569}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001570
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001571static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1572 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001573{
1574 struct mgmt_mode *cp = data;
1575 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001576 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001577 int err;
1578
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001579 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001580
Johan Hedberge6fe7982013-10-02 15:45:22 +03001581 status = mgmt_bredr_support(hdev);
1582 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001583 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001584 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001585
Johan Hedberga7e80f22013-01-09 16:05:19 +02001586 if (cp->val != 0x00 && cp->val != 0x01)
1587 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1588 MGMT_STATUS_INVALID_PARAMS);
1589
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001590 hci_dev_lock(hdev);
1591
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001592 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001593 bool changed = false;
1594
1595 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001596 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001597 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1598 changed = true;
1599 }
1600
1601 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1602 if (err < 0)
1603 goto failed;
1604
1605 if (changed)
1606 err = new_settings(hdev, sk);
1607
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001608 goto failed;
1609 }
1610
1611 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001612 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001613 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001614 goto failed;
1615 }
1616
1617 val = !!cp->val;
1618
1619 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1620 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1621 goto failed;
1622 }
1623
1624 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1625 if (!cmd) {
1626 err = -ENOMEM;
1627 goto failed;
1628 }
1629
1630 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1631 if (err < 0) {
1632 mgmt_pending_remove(cmd);
1633 goto failed;
1634 }
1635
1636failed:
1637 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001638 return err;
1639}
1640
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001641static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001642{
1643 struct mgmt_mode *cp = data;
1644 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001645 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001646 int err;
1647
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001648 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001649
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001650 status = mgmt_bredr_support(hdev);
1651 if (status)
1652 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1653
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001654 if (!lmp_ssp_capable(hdev))
1655 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1656 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001657
Johan Hedberga7e80f22013-01-09 16:05:19 +02001658 if (cp->val != 0x00 && cp->val != 0x01)
1659 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1660 MGMT_STATUS_INVALID_PARAMS);
1661
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001662 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001663
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001664 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001665 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001666
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001667 if (cp->val) {
1668 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1669 &hdev->dev_flags);
1670 } else {
1671 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1672 &hdev->dev_flags);
1673 if (!changed)
1674 changed = test_and_clear_bit(HCI_HS_ENABLED,
1675 &hdev->dev_flags);
1676 else
1677 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001678 }
1679
1680 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1681 if (err < 0)
1682 goto failed;
1683
1684 if (changed)
1685 err = new_settings(hdev, sk);
1686
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001687 goto failed;
1688 }
1689
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001690 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1691 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001692 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1693 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001694 goto failed;
1695 }
1696
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001697 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001698 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1699 goto failed;
1700 }
1701
1702 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1703 if (!cmd) {
1704 err = -ENOMEM;
1705 goto failed;
1706 }
1707
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001708 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001709 if (err < 0) {
1710 mgmt_pending_remove(cmd);
1711 goto failed;
1712 }
1713
1714failed:
1715 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001716 return err;
1717}
1718
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001719static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001720{
1721 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001722 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001723 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001724 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001725
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001726 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001727
Johan Hedberge6fe7982013-10-02 15:45:22 +03001728 status = mgmt_bredr_support(hdev);
1729 if (status)
1730 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001731
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001732 if (!lmp_ssp_capable(hdev))
1733 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1734 MGMT_STATUS_NOT_SUPPORTED);
1735
1736 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1737 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1738 MGMT_STATUS_REJECTED);
1739
Johan Hedberga7e80f22013-01-09 16:05:19 +02001740 if (cp->val != 0x00 && cp->val != 0x01)
1741 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1742 MGMT_STATUS_INVALID_PARAMS);
1743
Marcel Holtmannee392692013-10-01 22:59:23 -07001744 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001745
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001746 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001747 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001748 } else {
1749 if (hdev_is_powered(hdev)) {
1750 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1751 MGMT_STATUS_REJECTED);
1752 goto unlock;
1753 }
1754
Marcel Holtmannee392692013-10-01 22:59:23 -07001755 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001756 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001757
1758 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1759 if (err < 0)
1760 goto unlock;
1761
1762 if (changed)
1763 err = new_settings(hdev, sk);
1764
1765unlock:
1766 hci_dev_unlock(hdev);
1767 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001768}
1769
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001770static void le_enable_complete(struct hci_dev *hdev, u8 status)
1771{
1772 struct cmd_lookup match = { NULL, hdev };
1773
1774 if (status) {
1775 u8 mgmt_err = mgmt_status(status);
1776
1777 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1778 &mgmt_err);
1779 return;
1780 }
1781
1782 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1783
1784 new_settings(hdev, match.sk);
1785
1786 if (match.sk)
1787 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001788
1789 /* Make sure the controller has a good default for
1790 * advertising data. Restrict the update to when LE
1791 * has actually been enabled. During power on, the
1792 * update in powered_update_hci will take care of it.
1793 */
1794 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1795 struct hci_request req;
1796
1797 hci_dev_lock(hdev);
1798
1799 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001800 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07001801 update_scan_rsp_data(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001802 hci_req_run(&req, NULL);
1803
1804 hci_dev_unlock(hdev);
1805 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001806}
1807
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001808static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001809{
1810 struct mgmt_mode *cp = data;
1811 struct hci_cp_write_le_host_supported hci_cp;
1812 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001813 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001814 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001815 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001816
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001817 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001818
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001819 if (!lmp_le_capable(hdev))
1820 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1821 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001822
Johan Hedberga7e80f22013-01-09 16:05:19 +02001823 if (cp->val != 0x00 && cp->val != 0x01)
1824 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1825 MGMT_STATUS_INVALID_PARAMS);
1826
Johan Hedbergc73eee92013-04-19 18:35:21 +03001827 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001828 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001829 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1830 MGMT_STATUS_REJECTED);
1831
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001832 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001833
1834 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001835 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001836
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001837 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001838 bool changed = false;
1839
1840 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1841 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1842 changed = true;
1843 }
1844
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001845 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1846 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001847 changed = true;
1848 }
1849
Johan Hedberg06199cf2012-02-22 16:37:11 +02001850 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1851 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001852 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001853
1854 if (changed)
1855 err = new_settings(hdev, sk);
1856
Johan Hedberg1de028c2012-02-29 19:55:35 -08001857 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001858 }
1859
Johan Hedberg4375f102013-09-25 13:26:10 +03001860 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1861 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001862 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001863 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001864 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001865 }
1866
1867 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1868 if (!cmd) {
1869 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001870 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001871 }
1872
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001873 hci_req_init(&req, hdev);
1874
Johan Hedberg06199cf2012-02-22 16:37:11 +02001875 memset(&hci_cp, 0, sizeof(hci_cp));
1876
1877 if (val) {
1878 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001879 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001880 } else {
1881 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1882 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001883 }
1884
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001885 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1886 &hci_cp);
1887
1888 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301889 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001890 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001891
Johan Hedberg1de028c2012-02-29 19:55:35 -08001892unlock:
1893 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001894 return err;
1895}
1896
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001897/* This is a helper function to test for pending mgmt commands that can
1898 * cause CoD or EIR HCI commands. We can only allow one such pending
1899 * mgmt command at a time since otherwise we cannot easily track what
1900 * the current values are, will be, and based on that calculate if a new
1901 * HCI command needs to be sent and if yes with what value.
1902 */
1903static bool pending_eir_or_class(struct hci_dev *hdev)
1904{
1905 struct pending_cmd *cmd;
1906
1907 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1908 switch (cmd->opcode) {
1909 case MGMT_OP_ADD_UUID:
1910 case MGMT_OP_REMOVE_UUID:
1911 case MGMT_OP_SET_DEV_CLASS:
1912 case MGMT_OP_SET_POWERED:
1913 return true;
1914 }
1915 }
1916
1917 return false;
1918}
1919
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001920static const u8 bluetooth_base_uuid[] = {
1921 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1922 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1923};
1924
1925static u8 get_uuid_size(const u8 *uuid)
1926{
1927 u32 val;
1928
1929 if (memcmp(uuid, bluetooth_base_uuid, 12))
1930 return 128;
1931
1932 val = get_unaligned_le32(&uuid[12]);
1933 if (val > 0xffff)
1934 return 32;
1935
1936 return 16;
1937}
1938
Johan Hedberg92da6092013-03-15 17:06:55 -05001939static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1940{
1941 struct pending_cmd *cmd;
1942
1943 hci_dev_lock(hdev);
1944
1945 cmd = mgmt_pending_find(mgmt_op, hdev);
1946 if (!cmd)
1947 goto unlock;
1948
1949 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1950 hdev->dev_class, 3);
1951
1952 mgmt_pending_remove(cmd);
1953
1954unlock:
1955 hci_dev_unlock(hdev);
1956}
1957
1958static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1959{
1960 BT_DBG("status 0x%02x", status);
1961
1962 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1963}
1964
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001965static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001966{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001967 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001968 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001969 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001970 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001971 int err;
1972
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001973 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001974
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001975 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001976
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001977 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001978 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001979 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001980 goto failed;
1981 }
1982
Andre Guedes92c4c202012-06-07 19:05:44 -03001983 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001984 if (!uuid) {
1985 err = -ENOMEM;
1986 goto failed;
1987 }
1988
1989 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001990 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001991 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001992
Johan Hedbergde66aa62013-01-27 00:31:27 +02001993 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001994
Johan Hedberg890ea892013-03-15 17:06:52 -05001995 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001996
Johan Hedberg890ea892013-03-15 17:06:52 -05001997 update_class(&req);
1998 update_eir(&req);
1999
Johan Hedberg92da6092013-03-15 17:06:55 -05002000 err = hci_req_run(&req, add_uuid_complete);
2001 if (err < 0) {
2002 if (err != -ENODATA)
2003 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002004
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002005 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002006 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002007 goto failed;
2008 }
2009
2010 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002011 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002012 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002013 goto failed;
2014 }
2015
2016 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002017
2018failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002019 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002020 return err;
2021}
2022
Johan Hedberg24b78d02012-02-23 23:24:30 +02002023static bool enable_service_cache(struct hci_dev *hdev)
2024{
2025 if (!hdev_is_powered(hdev))
2026 return false;
2027
2028 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002029 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2030 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002031 return true;
2032 }
2033
2034 return false;
2035}
2036
Johan Hedberg92da6092013-03-15 17:06:55 -05002037static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
2038{
2039 BT_DBG("status 0x%02x", status);
2040
2041 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2042}
2043
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002044static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002045 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002046{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002047 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002048 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002049 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002050 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 -05002051 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002052 int err, found;
2053
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002054 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002055
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002056 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002057
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002058 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002059 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002060 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002061 goto unlock;
2062 }
2063
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002064 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
2065 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002066
Johan Hedberg24b78d02012-02-23 23:24:30 +02002067 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002068 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002069 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002070 goto unlock;
2071 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002072
Johan Hedberg9246a862012-02-23 21:33:16 +02002073 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002074 }
2075
2076 found = 0;
2077
Johan Hedberg056341c2013-01-27 00:31:30 +02002078 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002079 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2080 continue;
2081
2082 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002083 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002084 found++;
2085 }
2086
2087 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002088 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002089 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002090 goto unlock;
2091 }
2092
Johan Hedberg9246a862012-02-23 21:33:16 +02002093update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002094 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002095
Johan Hedberg890ea892013-03-15 17:06:52 -05002096 update_class(&req);
2097 update_eir(&req);
2098
Johan Hedberg92da6092013-03-15 17:06:55 -05002099 err = hci_req_run(&req, remove_uuid_complete);
2100 if (err < 0) {
2101 if (err != -ENODATA)
2102 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002103
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002104 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002105 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002106 goto unlock;
2107 }
2108
2109 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002110 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002111 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002112 goto unlock;
2113 }
2114
2115 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002116
2117unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002118 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002119 return err;
2120}
2121
Johan Hedberg92da6092013-03-15 17:06:55 -05002122static void set_class_complete(struct hci_dev *hdev, u8 status)
2123{
2124 BT_DBG("status 0x%02x", status);
2125
2126 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2127}
2128
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002129static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002130 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002131{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002132 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002133 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002134 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002135 int err;
2136
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002137 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002138
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002139 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002140 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2141 MGMT_STATUS_NOT_SUPPORTED);
2142
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002143 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002144
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002145 if (pending_eir_or_class(hdev)) {
2146 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2147 MGMT_STATUS_BUSY);
2148 goto unlock;
2149 }
2150
2151 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2152 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2153 MGMT_STATUS_INVALID_PARAMS);
2154 goto unlock;
2155 }
2156
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002157 hdev->major_class = cp->major;
2158 hdev->minor_class = cp->minor;
2159
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002160 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002161 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002162 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002163 goto unlock;
2164 }
2165
Johan Hedberg890ea892013-03-15 17:06:52 -05002166 hci_req_init(&req, hdev);
2167
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002168 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002169 hci_dev_unlock(hdev);
2170 cancel_delayed_work_sync(&hdev->service_cache);
2171 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002172 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002173 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002174
Johan Hedberg890ea892013-03-15 17:06:52 -05002175 update_class(&req);
2176
Johan Hedberg92da6092013-03-15 17:06:55 -05002177 err = hci_req_run(&req, set_class_complete);
2178 if (err < 0) {
2179 if (err != -ENODATA)
2180 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002181
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002182 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002183 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002184 goto unlock;
2185 }
2186
2187 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002188 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002189 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002190 goto unlock;
2191 }
2192
2193 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002194
Johan Hedbergb5235a62012-02-21 14:32:24 +02002195unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002196 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002197 return err;
2198}
2199
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002200static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002201 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002202{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002203 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002204 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002205 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002206
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002207 BT_DBG("request for %s", hdev->name);
2208
2209 if (!lmp_bredr_capable(hdev))
2210 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2211 MGMT_STATUS_NOT_SUPPORTED);
2212
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002213 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002214
Johan Hedberg86742e12011-11-07 23:13:38 +02002215 expected_len = sizeof(*cp) + key_count *
2216 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002217 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002218 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002219 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002220 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002221 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002222 }
2223
Johan Hedberg4ae143012013-01-20 14:27:13 +02002224 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2225 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2226 MGMT_STATUS_INVALID_PARAMS);
2227
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002228 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002229 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002230
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002231 for (i = 0; i < key_count; i++) {
2232 struct mgmt_link_key_info *key = &cp->keys[i];
2233
2234 if (key->addr.type != BDADDR_BREDR)
2235 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2236 MGMT_STATUS_INVALID_PARAMS);
2237 }
2238
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002239 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002240
2241 hci_link_keys_clear(hdev);
2242
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002243 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002244 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002245 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002246 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002247
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002248 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002249 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002250
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002251 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002252 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002253 }
2254
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002255 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002256
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002257 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002258
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002259 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002260}
2261
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002262static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002263 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002264{
2265 struct mgmt_ev_device_unpaired ev;
2266
2267 bacpy(&ev.addr.bdaddr, bdaddr);
2268 ev.addr.type = addr_type;
2269
2270 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002271 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002272}
2273
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002274static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002275 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002276{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002277 struct mgmt_cp_unpair_device *cp = data;
2278 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002279 struct hci_cp_disconnect dc;
2280 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002281 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002282 int err;
2283
Johan Hedberga8a1d192011-11-10 15:54:38 +02002284 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002285 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2286 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002287
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002288 if (!bdaddr_type_is_valid(cp->addr.type))
2289 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2290 MGMT_STATUS_INVALID_PARAMS,
2291 &rp, sizeof(rp));
2292
Johan Hedberg118da702013-01-20 14:27:20 +02002293 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2294 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2295 MGMT_STATUS_INVALID_PARAMS,
2296 &rp, sizeof(rp));
2297
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002298 hci_dev_lock(hdev);
2299
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002300 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002301 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002302 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002303 goto unlock;
2304 }
2305
Andre Guedes591f47f2012-04-24 21:02:49 -03002306 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02002307 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
2308 else
2309 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002310
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002311 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002312 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002313 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002314 goto unlock;
2315 }
2316
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002317 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002318 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002319 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002320 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002321 else
2322 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002323 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002324 } else {
2325 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002326 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002327
Johan Hedberga8a1d192011-11-10 15:54:38 +02002328 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002329 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002330 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002331 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002332 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002333 }
2334
Johan Hedberg124f6e32012-02-09 13:50:12 +02002335 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002336 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002337 if (!cmd) {
2338 err = -ENOMEM;
2339 goto unlock;
2340 }
2341
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002342 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002343 dc.reason = 0x13; /* Remote User Terminated Connection */
2344 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2345 if (err < 0)
2346 mgmt_pending_remove(cmd);
2347
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002348unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002349 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002350 return err;
2351}
2352
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002353static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002354 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002355{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002356 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002357 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002358 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002359 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002360 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002361 int err;
2362
2363 BT_DBG("");
2364
Johan Hedberg06a63b12013-01-20 14:27:21 +02002365 memset(&rp, 0, sizeof(rp));
2366 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2367 rp.addr.type = cp->addr.type;
2368
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002369 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002370 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2371 MGMT_STATUS_INVALID_PARAMS,
2372 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002373
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002374 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002375
2376 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002377 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2378 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002379 goto failed;
2380 }
2381
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002382 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002383 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2384 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002385 goto failed;
2386 }
2387
Andre Guedes591f47f2012-04-24 21:02:49 -03002388 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002389 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2390 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002391 else
2392 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002393
Vishal Agarwalf9607272012-06-13 05:32:43 +05302394 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002395 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2396 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002397 goto failed;
2398 }
2399
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002400 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002401 if (!cmd) {
2402 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002403 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002404 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002405
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002406 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002407 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002408
2409 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2410 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002411 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002412
2413failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002414 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002415 return err;
2416}
2417
Andre Guedes57c14772012-04-24 21:02:50 -03002418static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002419{
2420 switch (link_type) {
2421 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002422 switch (addr_type) {
2423 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002424 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002425
Johan Hedberg48264f02011-11-09 13:58:58 +02002426 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002427 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002428 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002429 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002430
Johan Hedberg4c659c32011-11-07 23:13:39 +02002431 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002432 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002433 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002434 }
2435}
2436
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002437static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2438 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002439{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002440 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002441 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002442 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002443 int err;
2444 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002445
2446 BT_DBG("");
2447
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002448 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002449
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002450 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002451 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002452 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002453 goto unlock;
2454 }
2455
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002456 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002457 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2458 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002459 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002460 }
2461
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002462 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002463 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002464 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002465 err = -ENOMEM;
2466 goto unlock;
2467 }
2468
Johan Hedberg2784eb42011-01-21 13:56:35 +02002469 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002470 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002471 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2472 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002473 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002474 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002475 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002476 continue;
2477 i++;
2478 }
2479
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002480 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002481
Johan Hedberg4c659c32011-11-07 23:13:39 +02002482 /* Recalculate length in case of filtered SCO connections, etc */
2483 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002484
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002485 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002486 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002487
Johan Hedberga38528f2011-01-22 06:46:43 +02002488 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002489
2490unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002491 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002492 return err;
2493}
2494
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002495static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002496 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002497{
2498 struct pending_cmd *cmd;
2499 int err;
2500
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002501 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002502 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002503 if (!cmd)
2504 return -ENOMEM;
2505
Johan Hedbergd8457692012-02-17 14:24:57 +02002506 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002507 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002508 if (err < 0)
2509 mgmt_pending_remove(cmd);
2510
2511 return err;
2512}
2513
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002514static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002515 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002516{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002517 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002518 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002519 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002520 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002521 int err;
2522
2523 BT_DBG("");
2524
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002525 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002526
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002527 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002528 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002529 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002530 goto failed;
2531 }
2532
Johan Hedbergd8457692012-02-17 14:24:57 +02002533 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002534 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002535 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002536 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002537 goto failed;
2538 }
2539
2540 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002541 struct mgmt_cp_pin_code_neg_reply ncp;
2542
2543 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002544
2545 BT_ERR("PIN code is not 16 bytes long");
2546
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002547 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002548 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002549 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002550 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002551
2552 goto failed;
2553 }
2554
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002555 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002556 if (!cmd) {
2557 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002558 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002559 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002560
Johan Hedbergd8457692012-02-17 14:24:57 +02002561 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002562 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002563 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002564
2565 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2566 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002567 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002568
2569failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002570 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002571 return err;
2572}
2573
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002574static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2575 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002576{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002577 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002578
2579 BT_DBG("");
2580
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002581 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002582
2583 hdev->io_capability = cp->io_capability;
2584
2585 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002586 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002587
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002588 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002589
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002590 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2591 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002592}
2593
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002594static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002595{
2596 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002597 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002598
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002599 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002600 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2601 continue;
2602
Johan Hedberge9a416b2011-02-19 12:05:56 -03002603 if (cmd->user_data != conn)
2604 continue;
2605
2606 return cmd;
2607 }
2608
2609 return NULL;
2610}
2611
2612static void pairing_complete(struct pending_cmd *cmd, u8 status)
2613{
2614 struct mgmt_rp_pair_device rp;
2615 struct hci_conn *conn = cmd->user_data;
2616
Johan Hedbergba4e5642011-11-11 00:07:34 +02002617 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002618 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002619
Johan Hedbergaee9b212012-02-18 15:07:59 +02002620 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002621 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002622
2623 /* So we don't get further callbacks for this connection */
2624 conn->connect_cfm_cb = NULL;
2625 conn->security_cfm_cb = NULL;
2626 conn->disconn_cfm_cb = NULL;
2627
David Herrmann76a68ba2013-04-06 20:28:37 +02002628 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002629
Johan Hedberga664b5b2011-02-19 12:06:02 -03002630 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002631}
2632
2633static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2634{
2635 struct pending_cmd *cmd;
2636
2637 BT_DBG("status %u", status);
2638
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002639 cmd = find_pairing(conn);
2640 if (!cmd)
2641 BT_DBG("Unable to find a pending command");
2642 else
Johan Hedberge2113262012-02-18 15:20:03 +02002643 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002644}
2645
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302646static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2647{
2648 struct pending_cmd *cmd;
2649
2650 BT_DBG("status %u", status);
2651
2652 if (!status)
2653 return;
2654
2655 cmd = find_pairing(conn);
2656 if (!cmd)
2657 BT_DBG("Unable to find a pending command");
2658 else
2659 pairing_complete(cmd, mgmt_status(status));
2660}
2661
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002662static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002663 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002664{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002665 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002666 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002667 struct pending_cmd *cmd;
2668 u8 sec_level, auth_type;
2669 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002670 int err;
2671
2672 BT_DBG("");
2673
Szymon Jancf950a30e2013-01-18 12:48:07 +01002674 memset(&rp, 0, sizeof(rp));
2675 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2676 rp.addr.type = cp->addr.type;
2677
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002678 if (!bdaddr_type_is_valid(cp->addr.type))
2679 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2680 MGMT_STATUS_INVALID_PARAMS,
2681 &rp, sizeof(rp));
2682
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002683 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002684
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002685 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002686 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2687 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002688 goto unlock;
2689 }
2690
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002691 sec_level = BT_SECURITY_MEDIUM;
2692 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002693 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002694 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002695 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002696
Andre Guedes591f47f2012-04-24 21:02:49 -03002697 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002698 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2699 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002700 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002701 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2702 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002703
Ville Tervo30e76272011-02-22 16:10:53 -03002704 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002705 int status;
2706
2707 if (PTR_ERR(conn) == -EBUSY)
2708 status = MGMT_STATUS_BUSY;
2709 else
2710 status = MGMT_STATUS_CONNECT_FAILED;
2711
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002712 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002713 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002714 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002715 goto unlock;
2716 }
2717
2718 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002719 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002720 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002721 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002722 goto unlock;
2723 }
2724
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002725 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002726 if (!cmd) {
2727 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002728 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002729 goto unlock;
2730 }
2731
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002732 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002733 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002734 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302735 else
2736 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002737
Johan Hedberge9a416b2011-02-19 12:05:56 -03002738 conn->security_cfm_cb = pairing_complete_cb;
2739 conn->disconn_cfm_cb = pairing_complete_cb;
2740 conn->io_capability = cp->io_cap;
2741 cmd->user_data = conn;
2742
2743 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002744 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002745 pairing_complete(cmd, 0);
2746
2747 err = 0;
2748
2749unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002750 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002751 return err;
2752}
2753
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002754static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2755 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002756{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002757 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002758 struct pending_cmd *cmd;
2759 struct hci_conn *conn;
2760 int err;
2761
2762 BT_DBG("");
2763
Johan Hedberg28424702012-02-02 04:02:29 +02002764 hci_dev_lock(hdev);
2765
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002766 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002767 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002768 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002769 goto unlock;
2770 }
2771
Johan Hedberg28424702012-02-02 04:02:29 +02002772 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2773 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002774 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002775 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002776 goto unlock;
2777 }
2778
2779 conn = cmd->user_data;
2780
2781 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002782 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002783 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002784 goto unlock;
2785 }
2786
2787 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2788
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002789 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002790 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002791unlock:
2792 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002793 return err;
2794}
2795
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002796static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002797 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002798 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002799{
Johan Hedberga5c29682011-02-19 12:05:57 -03002800 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002801 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002802 int err;
2803
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002804 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002805
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002806 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002807 err = cmd_complete(sk, hdev->id, mgmt_op,
2808 MGMT_STATUS_NOT_POWERED, addr,
2809 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002810 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002811 }
2812
Johan Hedberg1707c602013-03-15 17:07:15 -05002813 if (addr->type == BDADDR_BREDR)
2814 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002815 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002816 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002817
Johan Hedberg272d90d2012-02-09 15:26:12 +02002818 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002819 err = cmd_complete(sk, hdev->id, mgmt_op,
2820 MGMT_STATUS_NOT_CONNECTED, addr,
2821 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002822 goto done;
2823 }
2824
Johan Hedberg1707c602013-03-15 17:07:15 -05002825 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002826 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002827 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002828
Brian Gix5fe57d92011-12-21 16:12:13 -08002829 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002830 err = cmd_complete(sk, hdev->id, mgmt_op,
2831 MGMT_STATUS_SUCCESS, addr,
2832 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002833 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002834 err = cmd_complete(sk, hdev->id, mgmt_op,
2835 MGMT_STATUS_FAILED, addr,
2836 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002837
Brian Gix47c15e22011-11-16 13:53:14 -08002838 goto done;
2839 }
2840
Johan Hedberg1707c602013-03-15 17:07:15 -05002841 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002842 if (!cmd) {
2843 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002844 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002845 }
2846
Brian Gix0df4c182011-11-16 13:53:13 -08002847 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002848 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2849 struct hci_cp_user_passkey_reply cp;
2850
Johan Hedberg1707c602013-03-15 17:07:15 -05002851 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002852 cp.passkey = passkey;
2853 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2854 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002855 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2856 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002857
Johan Hedberga664b5b2011-02-19 12:06:02 -03002858 if (err < 0)
2859 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002860
Brian Gix0df4c182011-11-16 13:53:13 -08002861done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002862 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002863 return err;
2864}
2865
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302866static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2867 void *data, u16 len)
2868{
2869 struct mgmt_cp_pin_code_neg_reply *cp = data;
2870
2871 BT_DBG("");
2872
Johan Hedberg1707c602013-03-15 17:07:15 -05002873 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302874 MGMT_OP_PIN_CODE_NEG_REPLY,
2875 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2876}
2877
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002878static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2879 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002880{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002881 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002882
2883 BT_DBG("");
2884
2885 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002886 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002887 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002888
Johan Hedberg1707c602013-03-15 17:07:15 -05002889 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002890 MGMT_OP_USER_CONFIRM_REPLY,
2891 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002892}
2893
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002894static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002895 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002896{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002897 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002898
2899 BT_DBG("");
2900
Johan Hedberg1707c602013-03-15 17:07:15 -05002901 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002902 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2903 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002904}
2905
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002906static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2907 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002908{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002909 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002910
2911 BT_DBG("");
2912
Johan Hedberg1707c602013-03-15 17:07:15 -05002913 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002914 MGMT_OP_USER_PASSKEY_REPLY,
2915 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002916}
2917
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002918static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002919 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002920{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002921 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002922
2923 BT_DBG("");
2924
Johan Hedberg1707c602013-03-15 17:07:15 -05002925 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002926 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2927 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002928}
2929
Johan Hedberg13928972013-03-15 17:07:00 -05002930static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002931{
Johan Hedberg13928972013-03-15 17:07:00 -05002932 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002933 struct hci_cp_write_local_name cp;
2934
Johan Hedberg13928972013-03-15 17:07:00 -05002935 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002936
Johan Hedberg890ea892013-03-15 17:06:52 -05002937 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002938}
2939
Johan Hedberg13928972013-03-15 17:07:00 -05002940static void set_name_complete(struct hci_dev *hdev, u8 status)
2941{
2942 struct mgmt_cp_set_local_name *cp;
2943 struct pending_cmd *cmd;
2944
2945 BT_DBG("status 0x%02x", status);
2946
2947 hci_dev_lock(hdev);
2948
2949 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2950 if (!cmd)
2951 goto unlock;
2952
2953 cp = cmd->param;
2954
2955 if (status)
2956 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2957 mgmt_status(status));
2958 else
2959 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2960 cp, sizeof(*cp));
2961
2962 mgmt_pending_remove(cmd);
2963
2964unlock:
2965 hci_dev_unlock(hdev);
2966}
2967
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002968static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002969 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002970{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002971 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002972 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002973 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002974 int err;
2975
2976 BT_DBG("");
2977
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002978 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002979
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002980 /* If the old values are the same as the new ones just return a
2981 * direct command complete event.
2982 */
2983 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2984 !memcmp(hdev->short_name, cp->short_name,
2985 sizeof(hdev->short_name))) {
2986 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2987 data, len);
2988 goto failed;
2989 }
2990
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002991 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002992
Johan Hedbergb5235a62012-02-21 14:32:24 +02002993 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002994 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002995
2996 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002997 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002998 if (err < 0)
2999 goto failed;
3000
3001 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003002 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003003
Johan Hedbergb5235a62012-02-21 14:32:24 +02003004 goto failed;
3005 }
3006
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003007 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003008 if (!cmd) {
3009 err = -ENOMEM;
3010 goto failed;
3011 }
3012
Johan Hedberg13928972013-03-15 17:07:00 -05003013 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3014
Johan Hedberg890ea892013-03-15 17:06:52 -05003015 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003016
3017 if (lmp_bredr_capable(hdev)) {
3018 update_name(&req);
3019 update_eir(&req);
3020 }
3021
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003022 /* The name is stored in the scan response data and so
3023 * no need to udpate the advertising data here.
3024 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003025 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003026 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003027
Johan Hedberg13928972013-03-15 17:07:00 -05003028 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003029 if (err < 0)
3030 mgmt_pending_remove(cmd);
3031
3032failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003033 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003034 return err;
3035}
3036
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003037static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003038 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003039{
Szymon Jancc35938b2011-03-22 13:12:21 +01003040 struct pending_cmd *cmd;
3041 int err;
3042
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003043 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003044
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003045 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003046
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003047 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003048 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003049 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003050 goto unlock;
3051 }
3052
Andre Guedes9a1a1992012-07-24 15:03:48 -03003053 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003054 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003055 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003056 goto unlock;
3057 }
3058
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003059 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003060 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003061 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003062 goto unlock;
3063 }
3064
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003065 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003066 if (!cmd) {
3067 err = -ENOMEM;
3068 goto unlock;
3069 }
3070
3071 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3072 if (err < 0)
3073 mgmt_pending_remove(cmd);
3074
3075unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003076 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003077 return err;
3078}
3079
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003080static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003081 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003082{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003083 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003084 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003085 int err;
3086
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003087 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003088
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003089 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003090
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003091 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003092 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01003093 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003094 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01003095 else
Szymon Janca6785be2012-12-13 15:11:21 +01003096 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003097
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003098 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003099 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003100
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003101 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003102 return err;
3103}
3104
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003105static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003106 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003107{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003108 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003109 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003110 int err;
3111
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003112 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003113
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003114 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003115
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003116 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003117 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003118 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003119 else
Szymon Janca6785be2012-12-13 15:11:21 +01003120 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003121
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003122 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003123 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003124
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003125 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003126 return err;
3127}
3128
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003129static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3130{
3131 struct pending_cmd *cmd;
3132 u8 type;
3133 int err;
3134
3135 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3136
3137 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3138 if (!cmd)
3139 return -ENOENT;
3140
3141 type = hdev->discovery.type;
3142
3143 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3144 &type, sizeof(type));
3145 mgmt_pending_remove(cmd);
3146
3147 return err;
3148}
3149
Andre Guedes7c307722013-04-30 15:29:28 -03003150static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3151{
3152 BT_DBG("status %d", status);
3153
3154 if (status) {
3155 hci_dev_lock(hdev);
3156 mgmt_start_discovery_failed(hdev, status);
3157 hci_dev_unlock(hdev);
3158 return;
3159 }
3160
3161 hci_dev_lock(hdev);
3162 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3163 hci_dev_unlock(hdev);
3164
3165 switch (hdev->discovery.type) {
3166 case DISCOV_TYPE_LE:
3167 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003168 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003169 break;
3170
3171 case DISCOV_TYPE_INTERLEAVED:
3172 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003173 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003174 break;
3175
3176 case DISCOV_TYPE_BREDR:
3177 break;
3178
3179 default:
3180 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3181 }
3182}
3183
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003184static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003185 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003186{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003187 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003188 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003189 struct hci_cp_le_set_scan_param param_cp;
3190 struct hci_cp_le_set_scan_enable enable_cp;
3191 struct hci_cp_inquiry inq_cp;
3192 struct hci_request req;
3193 /* General inquiry access code (GIAC) */
3194 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003195 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003196 int err;
3197
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003198 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003199
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003200 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003201
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003202 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003203 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003204 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003205 goto failed;
3206 }
3207
Andre Guedes642be6c2012-03-21 00:03:37 -03003208 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3209 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3210 MGMT_STATUS_BUSY);
3211 goto failed;
3212 }
3213
Johan Hedbergff9ef572012-01-04 14:23:45 +02003214 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003215 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003216 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003217 goto failed;
3218 }
3219
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003220 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003221 if (!cmd) {
3222 err = -ENOMEM;
3223 goto failed;
3224 }
3225
Andre Guedes4aab14e2012-02-17 20:39:36 -03003226 hdev->discovery.type = cp->type;
3227
Andre Guedes7c307722013-04-30 15:29:28 -03003228 hci_req_init(&req, hdev);
3229
Andre Guedes4aab14e2012-02-17 20:39:36 -03003230 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003231 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003232 status = mgmt_bredr_support(hdev);
3233 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003234 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003235 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003236 mgmt_pending_remove(cmd);
3237 goto failed;
3238 }
3239
Andre Guedes7c307722013-04-30 15:29:28 -03003240 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3241 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3242 MGMT_STATUS_BUSY);
3243 mgmt_pending_remove(cmd);
3244 goto failed;
3245 }
3246
3247 hci_inquiry_cache_flush(hdev);
3248
3249 memset(&inq_cp, 0, sizeof(inq_cp));
3250 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003251 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003252 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003253 break;
3254
3255 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003256 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003257 status = mgmt_le_support(hdev);
3258 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003259 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003260 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003261 mgmt_pending_remove(cmd);
3262 goto failed;
3263 }
3264
Andre Guedes7c307722013-04-30 15:29:28 -03003265 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003266 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003267 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3268 MGMT_STATUS_NOT_SUPPORTED);
3269 mgmt_pending_remove(cmd);
3270 goto failed;
3271 }
3272
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003273 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003274 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3275 MGMT_STATUS_REJECTED);
3276 mgmt_pending_remove(cmd);
3277 goto failed;
3278 }
3279
3280 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3281 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3282 MGMT_STATUS_BUSY);
3283 mgmt_pending_remove(cmd);
3284 goto failed;
3285 }
3286
3287 memset(&param_cp, 0, sizeof(param_cp));
3288 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003289 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3290 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmann79830f62013-10-18 16:38:09 -07003291 param_cp.own_address_type = hdev->own_addr_type;
Andre Guedes7c307722013-04-30 15:29:28 -03003292 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3293 &param_cp);
3294
3295 memset(&enable_cp, 0, sizeof(enable_cp));
3296 enable_cp.enable = LE_SCAN_ENABLE;
3297 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3298 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3299 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003300 break;
3301
Andre Guedesf39799f2012-02-17 20:39:35 -03003302 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003303 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3304 MGMT_STATUS_INVALID_PARAMS);
3305 mgmt_pending_remove(cmd);
3306 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003307 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003308
Andre Guedes7c307722013-04-30 15:29:28 -03003309 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003310 if (err < 0)
3311 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003312 else
3313 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003314
3315failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003316 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003317 return err;
3318}
3319
Andre Guedes1183fdc2013-04-30 15:29:35 -03003320static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3321{
3322 struct pending_cmd *cmd;
3323 int err;
3324
3325 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3326 if (!cmd)
3327 return -ENOENT;
3328
3329 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3330 &hdev->discovery.type, sizeof(hdev->discovery.type));
3331 mgmt_pending_remove(cmd);
3332
3333 return err;
3334}
3335
Andre Guedes0e05bba2013-04-30 15:29:33 -03003336static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3337{
3338 BT_DBG("status %d", status);
3339
3340 hci_dev_lock(hdev);
3341
3342 if (status) {
3343 mgmt_stop_discovery_failed(hdev, status);
3344 goto unlock;
3345 }
3346
3347 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3348
3349unlock:
3350 hci_dev_unlock(hdev);
3351}
3352
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003353static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003354 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003355{
Johan Hedbergd9306502012-02-20 23:25:18 +02003356 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003357 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003358 struct hci_cp_remote_name_req_cancel cp;
3359 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003360 struct hci_request req;
3361 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003362 int err;
3363
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003364 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003365
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003366 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003367
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003368 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003369 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003370 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3371 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003372 goto unlock;
3373 }
3374
3375 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003376 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003377 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3378 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003379 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003380 }
3381
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003382 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003383 if (!cmd) {
3384 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003385 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003386 }
3387
Andre Guedes0e05bba2013-04-30 15:29:33 -03003388 hci_req_init(&req, hdev);
3389
Andre Guedese0d9727e2012-03-20 15:15:36 -03003390 switch (hdev->discovery.state) {
3391 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003392 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3393 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3394 } else {
3395 cancel_delayed_work(&hdev->le_scan_disable);
3396
3397 memset(&enable_cp, 0, sizeof(enable_cp));
3398 enable_cp.enable = LE_SCAN_DISABLE;
3399 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3400 sizeof(enable_cp), &enable_cp);
3401 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003402
Andre Guedese0d9727e2012-03-20 15:15:36 -03003403 break;
3404
3405 case DISCOVERY_RESOLVING:
3406 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003407 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003408 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003409 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003410 err = cmd_complete(sk, hdev->id,
3411 MGMT_OP_STOP_DISCOVERY, 0,
3412 &mgmt_cp->type,
3413 sizeof(mgmt_cp->type));
3414 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3415 goto unlock;
3416 }
3417
3418 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003419 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3420 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003421
3422 break;
3423
3424 default:
3425 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003426
3427 mgmt_pending_remove(cmd);
3428 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3429 MGMT_STATUS_FAILED, &mgmt_cp->type,
3430 sizeof(mgmt_cp->type));
3431 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003432 }
3433
Andre Guedes0e05bba2013-04-30 15:29:33 -03003434 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003435 if (err < 0)
3436 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003437 else
3438 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003439
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003440unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003441 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003442 return err;
3443}
3444
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003445static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003446 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003447{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003448 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003449 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003450 int err;
3451
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003452 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003453
Johan Hedberg561aafb2012-01-04 13:31:59 +02003454 hci_dev_lock(hdev);
3455
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003456 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003457 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003458 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003459 goto failed;
3460 }
3461
Johan Hedberga198e7b2012-02-17 14:27:06 +02003462 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003463 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003464 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003465 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003466 goto failed;
3467 }
3468
3469 if (cp->name_known) {
3470 e->name_state = NAME_KNOWN;
3471 list_del(&e->list);
3472 } else {
3473 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02003474 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003475 }
3476
Johan Hedberge3846622013-01-09 15:29:33 +02003477 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3478 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003479
3480failed:
3481 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003482 return err;
3483}
3484
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003485static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003486 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003487{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003488 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003489 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003490 int err;
3491
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003492 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003493
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003494 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003495 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3496 MGMT_STATUS_INVALID_PARAMS,
3497 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003498
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003499 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003500
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003501 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003502 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003503 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003504 else
Szymon Janca6785be2012-12-13 15:11:21 +01003505 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003506
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003507 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003508 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003509
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003510 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003511
3512 return err;
3513}
3514
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003515static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003516 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003517{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003518 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003519 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003520 int err;
3521
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003522 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003523
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003524 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003525 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3526 MGMT_STATUS_INVALID_PARAMS,
3527 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003528
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003529 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003530
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003531 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003532 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003533 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003534 else
Szymon Janca6785be2012-12-13 15:11:21 +01003535 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003536
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003537 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003538 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003539
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003540 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003541
3542 return err;
3543}
3544
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003545static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3546 u16 len)
3547{
3548 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003549 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003550 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003551 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003552
3553 BT_DBG("%s", hdev->name);
3554
Szymon Jancc72d4b82012-03-16 16:02:57 +01003555 source = __le16_to_cpu(cp->source);
3556
3557 if (source > 0x0002)
3558 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3559 MGMT_STATUS_INVALID_PARAMS);
3560
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003561 hci_dev_lock(hdev);
3562
Szymon Jancc72d4b82012-03-16 16:02:57 +01003563 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003564 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3565 hdev->devid_product = __le16_to_cpu(cp->product);
3566 hdev->devid_version = __le16_to_cpu(cp->version);
3567
3568 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3569
Johan Hedberg890ea892013-03-15 17:06:52 -05003570 hci_req_init(&req, hdev);
3571 update_eir(&req);
3572 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003573
3574 hci_dev_unlock(hdev);
3575
3576 return err;
3577}
3578
Johan Hedberg4375f102013-09-25 13:26:10 +03003579static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3580{
3581 struct cmd_lookup match = { NULL, hdev };
3582
3583 if (status) {
3584 u8 mgmt_err = mgmt_status(status);
3585
3586 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3587 cmd_status_rsp, &mgmt_err);
3588 return;
3589 }
3590
3591 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3592 &match);
3593
3594 new_settings(hdev, match.sk);
3595
3596 if (match.sk)
3597 sock_put(match.sk);
3598}
3599
Marcel Holtmann21b51872013-10-10 09:47:53 -07003600static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3601 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003602{
3603 struct mgmt_mode *cp = data;
3604 struct pending_cmd *cmd;
3605 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003606 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003607 int err;
3608
3609 BT_DBG("request for %s", hdev->name);
3610
Johan Hedberge6fe7982013-10-02 15:45:22 +03003611 status = mgmt_le_support(hdev);
3612 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003613 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003614 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003615
3616 if (cp->val != 0x00 && cp->val != 0x01)
3617 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3618 MGMT_STATUS_INVALID_PARAMS);
3619
3620 hci_dev_lock(hdev);
3621
3622 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003623 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003624
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003625 /* The following conditions are ones which mean that we should
3626 * not do any HCI communication but directly send a mgmt
3627 * response to user space (after toggling the flag if
3628 * necessary).
3629 */
3630 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003631 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003632 bool changed = false;
3633
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003634 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3635 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003636 changed = true;
3637 }
3638
3639 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3640 if (err < 0)
3641 goto unlock;
3642
3643 if (changed)
3644 err = new_settings(hdev, sk);
3645
3646 goto unlock;
3647 }
3648
3649 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3650 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3651 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3652 MGMT_STATUS_BUSY);
3653 goto unlock;
3654 }
3655
3656 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3657 if (!cmd) {
3658 err = -ENOMEM;
3659 goto unlock;
3660 }
3661
3662 hci_req_init(&req, hdev);
3663
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003664 if (val)
3665 enable_advertising(&req);
3666 else
3667 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003668
3669 err = hci_req_run(&req, set_advertising_complete);
3670 if (err < 0)
3671 mgmt_pending_remove(cmd);
3672
3673unlock:
3674 hci_dev_unlock(hdev);
3675 return err;
3676}
3677
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003678static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3679 void *data, u16 len)
3680{
3681 struct mgmt_cp_set_static_address *cp = data;
3682 int err;
3683
3684 BT_DBG("%s", hdev->name);
3685
Marcel Holtmann62af4442013-10-02 22:10:32 -07003686 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003687 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003688 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003689
3690 if (hdev_is_powered(hdev))
3691 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3692 MGMT_STATUS_REJECTED);
3693
3694 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3695 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3696 return cmd_status(sk, hdev->id,
3697 MGMT_OP_SET_STATIC_ADDRESS,
3698 MGMT_STATUS_INVALID_PARAMS);
3699
3700 /* Two most significant bits shall be set */
3701 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3702 return cmd_status(sk, hdev->id,
3703 MGMT_OP_SET_STATIC_ADDRESS,
3704 MGMT_STATUS_INVALID_PARAMS);
3705 }
3706
3707 hci_dev_lock(hdev);
3708
3709 bacpy(&hdev->static_addr, &cp->bdaddr);
3710
3711 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3712
3713 hci_dev_unlock(hdev);
3714
3715 return err;
3716}
3717
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003718static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3719 void *data, u16 len)
3720{
3721 struct mgmt_cp_set_scan_params *cp = data;
3722 __u16 interval, window;
3723 int err;
3724
3725 BT_DBG("%s", hdev->name);
3726
3727 if (!lmp_le_capable(hdev))
3728 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3729 MGMT_STATUS_NOT_SUPPORTED);
3730
3731 interval = __le16_to_cpu(cp->interval);
3732
3733 if (interval < 0x0004 || interval > 0x4000)
3734 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3735 MGMT_STATUS_INVALID_PARAMS);
3736
3737 window = __le16_to_cpu(cp->window);
3738
3739 if (window < 0x0004 || window > 0x4000)
3740 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3741 MGMT_STATUS_INVALID_PARAMS);
3742
Marcel Holtmann899e1072013-10-14 09:55:32 -07003743 if (window > interval)
3744 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3745 MGMT_STATUS_INVALID_PARAMS);
3746
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003747 hci_dev_lock(hdev);
3748
3749 hdev->le_scan_interval = interval;
3750 hdev->le_scan_window = window;
3751
3752 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3753
3754 hci_dev_unlock(hdev);
3755
3756 return err;
3757}
3758
Johan Hedberg33e38b32013-03-15 17:07:05 -05003759static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3760{
3761 struct pending_cmd *cmd;
3762
3763 BT_DBG("status 0x%02x", status);
3764
3765 hci_dev_lock(hdev);
3766
3767 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3768 if (!cmd)
3769 goto unlock;
3770
3771 if (status) {
3772 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3773 mgmt_status(status));
3774 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003775 struct mgmt_mode *cp = cmd->param;
3776
3777 if (cp->val)
3778 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3779 else
3780 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3781
Johan Hedberg33e38b32013-03-15 17:07:05 -05003782 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3783 new_settings(hdev, cmd->sk);
3784 }
3785
3786 mgmt_pending_remove(cmd);
3787
3788unlock:
3789 hci_dev_unlock(hdev);
3790}
3791
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003792static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003793 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003794{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003795 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003796 struct pending_cmd *cmd;
3797 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003798 int err;
3799
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003800 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003801
Johan Hedberg56f87902013-10-02 13:43:13 +03003802 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3803 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003804 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3805 MGMT_STATUS_NOT_SUPPORTED);
3806
Johan Hedberga7e80f22013-01-09 16:05:19 +02003807 if (cp->val != 0x00 && cp->val != 0x01)
3808 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3809 MGMT_STATUS_INVALID_PARAMS);
3810
Johan Hedberg5400c042012-02-21 16:40:33 +02003811 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003812 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003813 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003814
3815 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003816 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003817 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003818
3819 hci_dev_lock(hdev);
3820
Johan Hedberg05cbf292013-03-15 17:07:07 -05003821 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3822 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3823 MGMT_STATUS_BUSY);
3824 goto unlock;
3825 }
3826
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003827 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3828 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3829 hdev);
3830 goto unlock;
3831 }
3832
Johan Hedberg33e38b32013-03-15 17:07:05 -05003833 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3834 data, len);
3835 if (!cmd) {
3836 err = -ENOMEM;
3837 goto unlock;
3838 }
3839
3840 hci_req_init(&req, hdev);
3841
Johan Hedberg406d7802013-03-15 17:07:09 -05003842 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003843
3844 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003845 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003846 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003847 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003848 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003849 }
3850
Johan Hedberg33e38b32013-03-15 17:07:05 -05003851unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003852 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003853
Antti Julkuf6422ec2011-06-22 13:11:56 +03003854 return err;
3855}
3856
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003857static void set_bredr_scan(struct hci_request *req)
3858{
3859 struct hci_dev *hdev = req->hdev;
3860 u8 scan = 0;
3861
3862 /* Ensure that fast connectable is disabled. This function will
3863 * not do anything if the page scan parameters are already what
3864 * they should be.
3865 */
3866 write_fast_connectable(req, false);
3867
3868 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3869 scan |= SCAN_PAGE;
3870 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3871 scan |= SCAN_INQUIRY;
3872
3873 if (scan)
3874 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3875}
3876
Johan Hedberg0663ca22013-10-02 13:43:14 +03003877static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3878{
3879 struct pending_cmd *cmd;
3880
3881 BT_DBG("status 0x%02x", status);
3882
3883 hci_dev_lock(hdev);
3884
3885 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3886 if (!cmd)
3887 goto unlock;
3888
3889 if (status) {
3890 u8 mgmt_err = mgmt_status(status);
3891
3892 /* We need to restore the flag if related HCI commands
3893 * failed.
3894 */
3895 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3896
3897 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3898 } else {
3899 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3900 new_settings(hdev, cmd->sk);
3901 }
3902
3903 mgmt_pending_remove(cmd);
3904
3905unlock:
3906 hci_dev_unlock(hdev);
3907}
3908
3909static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3910{
3911 struct mgmt_mode *cp = data;
3912 struct pending_cmd *cmd;
3913 struct hci_request req;
3914 int err;
3915
3916 BT_DBG("request for %s", hdev->name);
3917
3918 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3919 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3920 MGMT_STATUS_NOT_SUPPORTED);
3921
3922 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3923 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3924 MGMT_STATUS_REJECTED);
3925
3926 if (cp->val != 0x00 && cp->val != 0x01)
3927 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3928 MGMT_STATUS_INVALID_PARAMS);
3929
3930 hci_dev_lock(hdev);
3931
3932 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3933 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3934 goto unlock;
3935 }
3936
3937 if (!hdev_is_powered(hdev)) {
3938 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003939 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3940 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3941 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3942 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3943 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3944 }
3945
3946 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3947
3948 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3949 if (err < 0)
3950 goto unlock;
3951
3952 err = new_settings(hdev, sk);
3953 goto unlock;
3954 }
3955
3956 /* Reject disabling when powered on */
3957 if (!cp->val) {
3958 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3959 MGMT_STATUS_REJECTED);
3960 goto unlock;
3961 }
3962
3963 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3964 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3965 MGMT_STATUS_BUSY);
3966 goto unlock;
3967 }
3968
3969 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3970 if (!cmd) {
3971 err = -ENOMEM;
3972 goto unlock;
3973 }
3974
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07003975 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03003976 * generates the correct flags.
3977 */
3978 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3979
3980 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003981
3982 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3983 set_bredr_scan(&req);
3984
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07003985 /* Since only the advertising data flags will change, there
3986 * is no need to update the scan response data.
3987 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07003988 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003989
Johan Hedberg0663ca22013-10-02 13:43:14 +03003990 err = hci_req_run(&req, set_bredr_complete);
3991 if (err < 0)
3992 mgmt_pending_remove(cmd);
3993
3994unlock:
3995 hci_dev_unlock(hdev);
3996 return err;
3997}
3998
Johan Hedberg3f706b72013-01-20 14:27:16 +02003999static bool ltk_is_valid(struct mgmt_ltk_info *key)
4000{
Johan Hedberg44b20d32013-01-20 14:27:17 +02004001 if (key->authenticated != 0x00 && key->authenticated != 0x01)
4002 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004003 if (key->master != 0x00 && key->master != 0x01)
4004 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004005 if (!bdaddr_type_is_le(key->addr.type))
4006 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004007 return true;
4008}
4009
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004010static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004011 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004012{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004013 struct mgmt_cp_load_long_term_keys *cp = cp_data;
4014 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004015 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004016
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004017 BT_DBG("request for %s", hdev->name);
4018
4019 if (!lmp_le_capable(hdev))
4020 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4021 MGMT_STATUS_NOT_SUPPORTED);
4022
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004023 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004024
4025 expected_len = sizeof(*cp) + key_count *
4026 sizeof(struct mgmt_ltk_info);
4027 if (expected_len != len) {
4028 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004029 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004030 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02004031 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004032 }
4033
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004034 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004035
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004036 for (i = 0; i < key_count; i++) {
4037 struct mgmt_ltk_info *key = &cp->keys[i];
4038
Johan Hedberg3f706b72013-01-20 14:27:16 +02004039 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004040 return cmd_status(sk, hdev->id,
4041 MGMT_OP_LOAD_LONG_TERM_KEYS,
4042 MGMT_STATUS_INVALID_PARAMS);
4043 }
4044
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004045 hci_dev_lock(hdev);
4046
4047 hci_smp_ltks_clear(hdev);
4048
4049 for (i = 0; i < key_count; i++) {
4050 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004051 u8 type, addr_type;
4052
4053 if (key->addr.type == BDADDR_LE_PUBLIC)
4054 addr_type = ADDR_LE_DEV_PUBLIC;
4055 else
4056 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004057
4058 if (key->master)
4059 type = HCI_SMP_LTK;
4060 else
4061 type = HCI_SMP_LTK_SLAVE;
4062
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004063 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004064 type, 0, key->authenticated, key->val,
4065 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004066 }
4067
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004068 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4069 NULL, 0);
4070
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004071 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004072
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004073 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004074}
4075
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004076static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004077 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4078 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004079 bool var_len;
4080 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004081} mgmt_handlers[] = {
4082 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004083 { read_version, false, MGMT_READ_VERSION_SIZE },
4084 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4085 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4086 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4087 { set_powered, false, MGMT_SETTING_SIZE },
4088 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4089 { set_connectable, false, MGMT_SETTING_SIZE },
4090 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4091 { set_pairable, false, MGMT_SETTING_SIZE },
4092 { set_link_security, false, MGMT_SETTING_SIZE },
4093 { set_ssp, false, MGMT_SETTING_SIZE },
4094 { set_hs, false, MGMT_SETTING_SIZE },
4095 { set_le, false, MGMT_SETTING_SIZE },
4096 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4097 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4098 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4099 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4100 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4101 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4102 { disconnect, false, MGMT_DISCONNECT_SIZE },
4103 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4104 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4105 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4106 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4107 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4108 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4109 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4110 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4111 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4112 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4113 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4114 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
4115 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
4116 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4117 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4118 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4119 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4120 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4121 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004122 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004123 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004124 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004125 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004126 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004127};
4128
4129
Johan Hedberg03811012010-12-08 00:21:06 +02004130int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4131{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004132 void *buf;
4133 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004134 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004135 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004136 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004137 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004138 int err;
4139
4140 BT_DBG("got %zu bytes", msglen);
4141
4142 if (msglen < sizeof(*hdr))
4143 return -EINVAL;
4144
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004145 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004146 if (!buf)
4147 return -ENOMEM;
4148
4149 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4150 err = -EFAULT;
4151 goto done;
4152 }
4153
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004154 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004155 opcode = __le16_to_cpu(hdr->opcode);
4156 index = __le16_to_cpu(hdr->index);
4157 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004158
4159 if (len != msglen - sizeof(*hdr)) {
4160 err = -EINVAL;
4161 goto done;
4162 }
4163
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004164 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004165 hdev = hci_dev_get(index);
4166 if (!hdev) {
4167 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004168 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004169 goto done;
4170 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004171
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004172 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4173 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004174 err = cmd_status(sk, index, opcode,
4175 MGMT_STATUS_INVALID_INDEX);
4176 goto done;
4177 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004178 }
4179
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004180 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004181 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004182 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004183 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004184 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004185 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004186 }
4187
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004188 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004189 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004190 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004191 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004192 goto done;
4193 }
4194
Johan Hedbergbe22b542012-03-01 22:24:41 +02004195 handler = &mgmt_handlers[opcode];
4196
4197 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004198 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004199 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004200 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004201 goto done;
4202 }
4203
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004204 if (hdev)
4205 mgmt_init_hdev(sk, hdev);
4206
4207 cp = buf + sizeof(*hdr);
4208
Johan Hedbergbe22b542012-03-01 22:24:41 +02004209 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004210 if (err < 0)
4211 goto done;
4212
Johan Hedberg03811012010-12-08 00:21:06 +02004213 err = msglen;
4214
4215done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004216 if (hdev)
4217 hci_dev_put(hdev);
4218
Johan Hedberg03811012010-12-08 00:21:06 +02004219 kfree(buf);
4220 return err;
4221}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004222
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004223void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004224{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004225 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004226 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004227
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004228 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004229}
4230
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004231void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004232{
Johan Hedberg5f159032012-03-02 03:13:19 +02004233 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004234
Marcel Holtmann1514b892013-10-06 08:25:01 -07004235 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004236 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004237
Johan Hedberg744cf192011-11-08 20:40:14 +02004238 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004239
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004240 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004241}
4242
Johan Hedberg229ab392013-03-15 17:06:53 -05004243static void powered_complete(struct hci_dev *hdev, u8 status)
4244{
4245 struct cmd_lookup match = { NULL, hdev };
4246
4247 BT_DBG("status 0x%02x", status);
4248
4249 hci_dev_lock(hdev);
4250
4251 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4252
4253 new_settings(hdev, match.sk);
4254
4255 hci_dev_unlock(hdev);
4256
4257 if (match.sk)
4258 sock_put(match.sk);
4259}
4260
Johan Hedberg70da6242013-03-15 17:06:51 -05004261static int powered_update_hci(struct hci_dev *hdev)
4262{
Johan Hedberg890ea892013-03-15 17:06:52 -05004263 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004264 u8 link_sec;
4265
Johan Hedberg890ea892013-03-15 17:06:52 -05004266 hci_req_init(&req, hdev);
4267
Johan Hedberg70da6242013-03-15 17:06:51 -05004268 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4269 !lmp_host_ssp_capable(hdev)) {
4270 u8 ssp = 1;
4271
Johan Hedberg890ea892013-03-15 17:06:52 -05004272 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004273 }
4274
Johan Hedbergc73eee92013-04-19 18:35:21 +03004275 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4276 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004277 struct hci_cp_write_le_host_supported cp;
4278
4279 cp.le = 1;
4280 cp.simul = lmp_le_br_capable(hdev);
4281
4282 /* Check first if we already have the right
4283 * host state (host features set)
4284 */
4285 if (cp.le != lmp_host_le_capable(hdev) ||
4286 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004287 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4288 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004289 }
4290
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004291 if (lmp_le_capable(hdev)) {
4292 /* Set random address to static address if configured */
4293 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4294 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4295 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004296
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004297 /* Make sure the controller has a good default for
4298 * advertising data. This also applies to the case
4299 * where BR/EDR was toggled during the AUTO_OFF phase.
4300 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004301 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004302 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004303 update_scan_rsp_data(&req);
4304 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004305
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004306 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4307 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004308 }
4309
Johan Hedberg70da6242013-03-15 17:06:51 -05004310 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4311 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004312 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4313 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004314
4315 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004316 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4317 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004318 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004319 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004320 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004321 }
4322
Johan Hedberg229ab392013-03-15 17:06:53 -05004323 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004324}
4325
Johan Hedberg744cf192011-11-08 20:40:14 +02004326int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004327{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004328 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004329 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4330 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004331 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004332
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004333 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4334 return 0;
4335
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004336 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004337 if (powered_update_hci(hdev) == 0)
4338 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004339
Johan Hedberg229ab392013-03-15 17:06:53 -05004340 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4341 &match);
4342 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004343 }
4344
Johan Hedberg229ab392013-03-15 17:06:53 -05004345 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4346 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4347
4348 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4349 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4350 zero_cod, sizeof(zero_cod), NULL);
4351
4352new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004353 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004354
4355 if (match.sk)
4356 sock_put(match.sk);
4357
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004358 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004359}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004360
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004361void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004362{
4363 struct pending_cmd *cmd;
4364 u8 status;
4365
4366 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4367 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004368 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004369
4370 if (err == -ERFKILL)
4371 status = MGMT_STATUS_RFKILLED;
4372 else
4373 status = MGMT_STATUS_FAILED;
4374
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004375 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004376
4377 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004378}
4379
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004380void mgmt_discoverable_timeout(struct hci_dev *hdev)
4381{
4382 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004383
4384 hci_dev_lock(hdev);
4385
4386 /* When discoverable timeout triggers, then just make sure
4387 * the limited discoverable flag is cleared. Even in the case
4388 * of a timeout triggered from general discoverable, it is
4389 * safe to unconditionally clear the flag.
4390 */
4391 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004392 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004393
4394 hci_req_init(&req, hdev);
Johan Hedberg4b580612013-10-19 23:38:21 +03004395 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4396 u8 scan = SCAN_PAGE;
4397 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
4398 sizeof(scan), &scan);
4399 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004400 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004401 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004402 hci_req_run(&req, NULL);
4403
4404 hdev->discov_timeout = 0;
4405
Johan Hedberg9a43e252013-10-20 19:00:07 +03004406 new_settings(hdev, NULL);
4407
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004408 hci_dev_unlock(hdev);
4409}
4410
Marcel Holtmann86a75642013-10-15 06:33:54 -07004411void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004412{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004413 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004414
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004415 /* Nothing needed here if there's a pending command since that
4416 * commands request completion callback takes care of everything
4417 * necessary.
4418 */
4419 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004420 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004421
Johan Hedberg9a43e252013-10-20 19:00:07 +03004422 if (discoverable) {
Marcel Holtmann86a75642013-10-15 06:33:54 -07004423 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004424 } else {
4425 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmann86a75642013-10-15 06:33:54 -07004426 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004427 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004428
Johan Hedberg9a43e252013-10-20 19:00:07 +03004429 if (changed) {
4430 struct hci_request req;
4431
4432 /* In case this change in discoverable was triggered by
4433 * a disabling of connectable there could be a need to
4434 * update the advertising flags.
4435 */
4436 hci_req_init(&req, hdev);
4437 update_adv_data(&req);
4438 hci_req_run(&req, NULL);
4439
Marcel Holtmann86a75642013-10-15 06:33:54 -07004440 new_settings(hdev, NULL);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004441 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004442}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004443
Marcel Holtmanna3309162013-10-15 06:33:55 -07004444void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004445{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004446 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004447
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004448 /* Nothing needed here if there's a pending command since that
4449 * commands request completion callback takes care of everything
4450 * necessary.
4451 */
4452 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004453 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004454
Marcel Holtmanna3309162013-10-15 06:33:55 -07004455 if (connectable)
4456 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4457 else
4458 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004459
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004460 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004461 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004462}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004463
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004464void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004465{
Johan Hedbergca69b792011-11-11 18:10:00 +02004466 u8 mgmt_err = mgmt_status(status);
4467
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004468 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004469 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004470 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004471
4472 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004473 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004474 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004475}
4476
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004477void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4478 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004479{
Johan Hedberg86742e12011-11-07 23:13:38 +02004480 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004481
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004482 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004483
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004484 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004485 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004486 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004487 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004488 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004489 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004490
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004491 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004492}
Johan Hedbergf7520542011-01-20 12:34:39 +02004493
Marcel Holtmann083368f2013-10-15 14:26:29 -07004494void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004495{
4496 struct mgmt_ev_new_long_term_key ev;
4497
4498 memset(&ev, 0, sizeof(ev));
4499
4500 ev.store_hint = persistent;
4501 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004502 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004503 ev.key.authenticated = key->authenticated;
4504 ev.key.enc_size = key->enc_size;
4505 ev.key.ediv = key->ediv;
4506
4507 if (key->type == HCI_SMP_LTK)
4508 ev.key.master = 1;
4509
4510 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4511 memcpy(ev.key.val, key->val, sizeof(key->val));
4512
Marcel Holtmann083368f2013-10-15 14:26:29 -07004513 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004514}
4515
Marcel Holtmann94933992013-10-15 10:26:39 -07004516static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4517 u8 data_len)
4518{
4519 eir[eir_len++] = sizeof(type) + data_len;
4520 eir[eir_len++] = type;
4521 memcpy(&eir[eir_len], data, data_len);
4522 eir_len += data_len;
4523
4524 return eir_len;
4525}
4526
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004527void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4528 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4529 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004530{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004531 char buf[512];
4532 struct mgmt_ev_device_connected *ev = (void *) buf;
4533 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004534
Johan Hedbergb644ba32012-01-17 21:48:47 +02004535 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004536 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004537
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004538 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004539
Johan Hedbergb644ba32012-01-17 21:48:47 +02004540 if (name_len > 0)
4541 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004542 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004543
4544 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004545 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004546 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004547
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004548 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004549
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004550 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4551 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004552}
4553
Johan Hedberg8962ee72011-01-20 12:40:27 +02004554static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4555{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004556 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004557 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004558 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004559
Johan Hedberg88c3df12012-02-09 14:27:38 +02004560 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4561 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004562
Johan Hedbergaee9b212012-02-18 15:07:59 +02004563 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004564 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004565
4566 *sk = cmd->sk;
4567 sock_hold(*sk);
4568
Johan Hedberga664b5b2011-02-19 12:06:02 -03004569 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004570}
4571
Johan Hedberg124f6e32012-02-09 13:50:12 +02004572static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004573{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004574 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004575 struct mgmt_cp_unpair_device *cp = cmd->param;
4576 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004577
4578 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004579 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4580 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004581
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004582 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4583
Johan Hedbergaee9b212012-02-18 15:07:59 +02004584 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004585
4586 mgmt_pending_remove(cmd);
4587}
4588
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004589void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4590 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004591{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004592 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004593 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004594
Johan Hedberg744cf192011-11-08 20:40:14 +02004595 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004596
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004597 bacpy(&ev.addr.bdaddr, bdaddr);
4598 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4599 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004600
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004601 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004602
4603 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004604 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004605
Johan Hedberg124f6e32012-02-09 13:50:12 +02004606 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004607 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004608}
4609
Marcel Holtmann78929242013-10-06 23:55:47 -07004610void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4611 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004612{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004613 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004614 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004615
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004616 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4617 hdev);
4618
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004619 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004620 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004621 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004622
Johan Hedberg88c3df12012-02-09 14:27:38 +02004623 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004624 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004625
Marcel Holtmann78929242013-10-06 23:55:47 -07004626 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4627 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004628
Johan Hedberga664b5b2011-02-19 12:06:02 -03004629 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004630}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004631
Marcel Holtmann445608d2013-10-06 23:55:48 -07004632void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4633 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004634{
4635 struct mgmt_ev_connect_failed ev;
4636
Johan Hedberg4c659c32011-11-07 23:13:39 +02004637 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004638 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004639 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004640
Marcel Holtmann445608d2013-10-06 23:55:48 -07004641 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004642}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004643
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004644void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004645{
4646 struct mgmt_ev_pin_code_request ev;
4647
Johan Hedbergd8457692012-02-17 14:24:57 +02004648 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004649 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004650 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004651
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004652 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004653}
4654
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004655void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4656 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004657{
4658 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004659 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004660
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004661 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004662 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004663 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004664
Johan Hedbergd8457692012-02-17 14:24:57 +02004665 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004666 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004667
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004668 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
4669 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004670
Johan Hedberga664b5b2011-02-19 12:06:02 -03004671 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004672}
4673
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004674void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4675 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004676{
4677 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004678 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004679
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004680 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004681 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004682 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004683
Johan Hedbergd8457692012-02-17 14:24:57 +02004684 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004685 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004686
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004687 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
4688 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004689
Johan Hedberga664b5b2011-02-19 12:06:02 -03004690 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004691}
Johan Hedberga5c29682011-02-19 12:05:57 -03004692
Johan Hedberg744cf192011-11-08 20:40:14 +02004693int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004694 u8 link_type, u8 addr_type, __le32 value,
4695 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004696{
4697 struct mgmt_ev_user_confirm_request ev;
4698
Johan Hedberg744cf192011-11-08 20:40:14 +02004699 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004700
Johan Hedberg272d90d2012-02-09 15:26:12 +02004701 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004702 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004703 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004704 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004705
Johan Hedberg744cf192011-11-08 20:40:14 +02004706 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004707 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004708}
4709
Johan Hedberg272d90d2012-02-09 15:26:12 +02004710int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004711 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004712{
4713 struct mgmt_ev_user_passkey_request ev;
4714
4715 BT_DBG("%s", hdev->name);
4716
Johan Hedberg272d90d2012-02-09 15:26:12 +02004717 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004718 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004719
4720 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004721 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004722}
4723
Brian Gix0df4c182011-11-16 13:53:13 -08004724static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004725 u8 link_type, u8 addr_type, u8 status,
4726 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004727{
4728 struct pending_cmd *cmd;
4729 struct mgmt_rp_user_confirm_reply rp;
4730 int err;
4731
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004732 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004733 if (!cmd)
4734 return -ENOENT;
4735
Johan Hedberg272d90d2012-02-09 15:26:12 +02004736 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004737 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004738 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004739 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004740
Johan Hedberga664b5b2011-02-19 12:06:02 -03004741 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004742
4743 return err;
4744}
4745
Johan Hedberg744cf192011-11-08 20:40:14 +02004746int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004747 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004748{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004749 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004750 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004751}
4752
Johan Hedberg272d90d2012-02-09 15:26:12 +02004753int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004754 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004755{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004756 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004757 status,
4758 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004759}
Johan Hedberg2a611692011-02-19 12:06:00 -03004760
Brian Gix604086b2011-11-23 08:28:33 -08004761int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004762 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004763{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004764 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004765 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004766}
4767
Johan Hedberg272d90d2012-02-09 15:26:12 +02004768int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004769 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004770{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004771 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004772 status,
4773 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004774}
4775
Johan Hedberg92a25252012-09-06 18:39:26 +03004776int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4777 u8 link_type, u8 addr_type, u32 passkey,
4778 u8 entered)
4779{
4780 struct mgmt_ev_passkey_notify ev;
4781
4782 BT_DBG("%s", hdev->name);
4783
4784 bacpy(&ev.addr.bdaddr, bdaddr);
4785 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4786 ev.passkey = __cpu_to_le32(passkey);
4787 ev.entered = entered;
4788
4789 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4790}
4791
Marcel Holtmanne5460992013-10-15 14:26:23 -07004792void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4793 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004794{
4795 struct mgmt_ev_auth_failed ev;
4796
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004797 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004798 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004799 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004800
Marcel Holtmanne5460992013-10-15 14:26:23 -07004801 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004802}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004803
Marcel Holtmann464996a2013-10-15 14:26:24 -07004804void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004805{
4806 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07004807 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004808
4809 if (status) {
4810 u8 mgmt_err = mgmt_status(status);
4811 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004812 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07004813 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004814 }
4815
Marcel Holtmann464996a2013-10-15 14:26:24 -07004816 if (test_bit(HCI_AUTH, &hdev->flags))
4817 changed = !test_and_set_bit(HCI_LINK_SECURITY,
4818 &hdev->dev_flags);
4819 else
4820 changed = test_and_clear_bit(HCI_LINK_SECURITY,
4821 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02004822
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004823 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004824 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004825
Johan Hedberg47990ea2012-02-22 11:58:37 +02004826 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07004827 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004828
4829 if (match.sk)
4830 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004831}
4832
Johan Hedberg890ea892013-03-15 17:06:52 -05004833static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004834{
Johan Hedberg890ea892013-03-15 17:06:52 -05004835 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004836 struct hci_cp_write_eir cp;
4837
Johan Hedberg976eb202012-10-24 21:12:01 +03004838 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004839 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004840
Johan Hedbergc80da272012-02-22 15:38:48 +02004841 memset(hdev->eir, 0, sizeof(hdev->eir));
4842
Johan Hedbergcacaf522012-02-21 00:52:42 +02004843 memset(&cp, 0, sizeof(cp));
4844
Johan Hedberg890ea892013-03-15 17:06:52 -05004845 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004846}
4847
Marcel Holtmann3e248562013-10-15 14:26:25 -07004848void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004849{
4850 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004851 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004852 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004853
4854 if (status) {
4855 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004856
4857 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004858 &hdev->dev_flags)) {
4859 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004860 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004861 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004862
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004863 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4864 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004865 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004866 }
4867
4868 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004869 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004870 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004871 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4872 if (!changed)
4873 changed = test_and_clear_bit(HCI_HS_ENABLED,
4874 &hdev->dev_flags);
4875 else
4876 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004877 }
4878
4879 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4880
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004881 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07004882 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004883
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004884 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004885 sock_put(match.sk);
4886
Johan Hedberg890ea892013-03-15 17:06:52 -05004887 hci_req_init(&req, hdev);
4888
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004889 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004890 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004891 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004892 clear_eir(&req);
4893
4894 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004895}
4896
Johan Hedberg92da6092013-03-15 17:06:55 -05004897static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004898{
4899 struct cmd_lookup *match = data;
4900
Johan Hedberg90e70452012-02-23 23:09:40 +02004901 if (match->sk == NULL) {
4902 match->sk = cmd->sk;
4903 sock_hold(match->sk);
4904 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004905}
4906
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07004907void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
4908 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004909{
Johan Hedberg90e70452012-02-23 23:09:40 +02004910 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004911
Johan Hedberg92da6092013-03-15 17:06:55 -05004912 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4913 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4914 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004915
4916 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07004917 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
4918 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004919
4920 if (match.sk)
4921 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004922}
4923
Marcel Holtmann7667da32013-10-15 14:26:27 -07004924void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004925{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004926 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004927 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004928
Johan Hedberg13928972013-03-15 17:07:00 -05004929 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07004930 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004931
4932 memset(&ev, 0, sizeof(ev));
4933 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004934 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004935
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004936 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004937 if (!cmd) {
4938 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004939
Johan Hedberg13928972013-03-15 17:07:00 -05004940 /* If this is a HCI command related to powering on the
4941 * HCI dev don't send any mgmt signals.
4942 */
4943 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07004944 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004945 }
4946
Marcel Holtmann7667da32013-10-15 14:26:27 -07004947 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4948 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004949}
Szymon Jancc35938b2011-03-22 13:12:21 +01004950
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004951void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
4952 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004953{
4954 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01004955
Johan Hedberg744cf192011-11-08 20:40:14 +02004956 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004957
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004958 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004959 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004960 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01004961
4962 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004963 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4964 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004965 } else {
4966 struct mgmt_rp_read_local_oob_data rp;
4967
4968 memcpy(rp.hash, hash, sizeof(rp.hash));
4969 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4970
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004971 cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4972 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004973 }
4974
4975 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01004976}
Johan Hedberge17acd42011-03-30 23:57:16 +03004977
Marcel Holtmann901801b2013-10-06 23:55:51 -07004978void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4979 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4980 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004981{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004982 char buf[512];
4983 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004984 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004985
Andre Guedes12602d02013-04-30 15:29:40 -03004986 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004987 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004988
Johan Hedberg1dc06092012-01-15 21:01:23 +02004989 /* Leave 5 bytes for a potential CoD field */
4990 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004991 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004992
Johan Hedberg1dc06092012-01-15 21:01:23 +02004993 memset(buf, 0, sizeof(buf));
4994
Johan Hedberge319d2e2012-01-15 19:51:59 +02004995 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004996 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004997 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004998 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304999 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02005000 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305001 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03005002
Johan Hedberg1dc06092012-01-15 21:01:23 +02005003 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02005004 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03005005
Johan Hedberg1dc06092012-01-15 21:01:23 +02005006 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
5007 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005008 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005009
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005010 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005011 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03005012
Marcel Holtmann901801b2013-10-06 23:55:51 -07005013 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03005014}
Johan Hedberga88a9652011-03-30 13:18:12 +03005015
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005016void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5017 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03005018{
Johan Hedbergb644ba32012-01-17 21:48:47 +02005019 struct mgmt_ev_device_found *ev;
5020 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
5021 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03005022
Johan Hedbergb644ba32012-01-17 21:48:47 +02005023 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03005024
Johan Hedbergb644ba32012-01-17 21:48:47 +02005025 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03005026
Johan Hedbergb644ba32012-01-17 21:48:47 +02005027 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005028 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005029 ev->rssi = rssi;
5030
5031 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005032 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005033
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005034 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005035
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005036 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03005037}
Johan Hedberg314b2382011-04-27 10:29:57 -04005038
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005039void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04005040{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005041 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02005042 struct pending_cmd *cmd;
5043
Andre Guedes343fb142011-11-22 17:14:19 -03005044 BT_DBG("%s discovering %u", hdev->name, discovering);
5045
Johan Hedberg164a6e72011-11-01 17:06:44 +02005046 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005047 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005048 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005049 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005050
5051 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02005052 u8 type = hdev->discovery.type;
5053
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005054 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
5055 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02005056 mgmt_pending_remove(cmd);
5057 }
5058
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005059 memset(&ev, 0, sizeof(ev));
5060 ev.type = hdev->discovery.type;
5061 ev.discovering = discovering;
5062
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005063 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04005064}
Antti Julku5e762442011-08-25 16:48:02 +03005065
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005066int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005067{
5068 struct pending_cmd *cmd;
5069 struct mgmt_ev_device_blocked ev;
5070
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005071 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005072
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005073 bacpy(&ev.addr.bdaddr, bdaddr);
5074 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005075
Johan Hedberg744cf192011-11-08 20:40:14 +02005076 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005077 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005078}
5079
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005080int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005081{
5082 struct pending_cmd *cmd;
5083 struct mgmt_ev_device_unblocked ev;
5084
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005085 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005086
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005087 bacpy(&ev.addr.bdaddr, bdaddr);
5088 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005089
Johan Hedberg744cf192011-11-08 20:40:14 +02005090 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005091 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005092}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005093
5094static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5095{
5096 BT_DBG("%s status %u", hdev->name, status);
5097
5098 /* Clear the advertising mgmt setting if we failed to re-enable it */
5099 if (status) {
5100 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005101 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005102 }
5103}
5104
5105void mgmt_reenable_advertising(struct hci_dev *hdev)
5106{
5107 struct hci_request req;
5108
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005109 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005110 return;
5111
5112 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5113 return;
5114
5115 hci_req_init(&req, hdev);
5116 enable_advertising(&req);
5117
5118 /* If this fails we have no option but to let user space know
5119 * that we've disabled advertising.
5120 */
5121 if (hci_req_run(&req, adv_enable_complete) < 0) {
5122 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005123 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005124 }
5125}