blob: 67b95a80f8294696b602d7e6e73862aa30958681 [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
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700602static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700603{
604 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700605
606 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
607 flags |= LE_AD_GENERAL;
608
609 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
610 if (lmp_le_br_capable(hdev))
611 flags |= LE_AD_SIM_LE_BREDR_CTRL;
612 if (lmp_host_le_br_capable(hdev))
613 flags |= LE_AD_SIM_LE_BREDR_HOST;
614 } else {
615 flags |= LE_AD_NO_BREDR;
616 }
617
618 if (flags) {
619 BT_DBG("adv flags 0x%02x", flags);
620
621 ptr[0] = 2;
622 ptr[1] = EIR_FLAGS;
623 ptr[2] = flags;
624
625 ad_len += 3;
626 ptr += 3;
627 }
628
629 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
630 ptr[0] = 2;
631 ptr[1] = EIR_TX_POWER;
632 ptr[2] = (u8) hdev->adv_tx_power;
633
634 ad_len += 3;
635 ptr += 3;
636 }
637
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700638 return ad_len;
639}
640
Marcel Holtmann5947f4b2013-10-16 00:16:50 -0700641static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700642{
643 struct hci_dev *hdev = req->hdev;
644 struct hci_cp_le_set_adv_data cp;
645 u8 len;
646
Johan Hedberg10994ce2013-10-19 23:38:16 +0300647 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700648 return;
649
650 memset(&cp, 0, sizeof(cp));
651
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700652 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700653
654 if (hdev->adv_data_len == len &&
655 memcmp(cp.data, hdev->adv_data, len) == 0)
656 return;
657
658 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
659 hdev->adv_data_len = len;
660
661 cp.length = len;
662
663 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
664}
665
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300666static void create_eir(struct hci_dev *hdev, u8 *data)
667{
668 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300669 size_t name_len;
670
671 name_len = strlen(hdev->dev_name);
672
673 if (name_len > 0) {
674 /* EIR Data type */
675 if (name_len > 48) {
676 name_len = 48;
677 ptr[1] = EIR_NAME_SHORT;
678 } else
679 ptr[1] = EIR_NAME_COMPLETE;
680
681 /* EIR Data length */
682 ptr[0] = name_len + 1;
683
684 memcpy(ptr + 2, hdev->dev_name, name_len);
685
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300686 ptr += (name_len + 2);
687 }
688
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100689 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700690 ptr[0] = 2;
691 ptr[1] = EIR_TX_POWER;
692 ptr[2] = (u8) hdev->inq_tx_power;
693
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700694 ptr += 3;
695 }
696
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700697 if (hdev->devid_source > 0) {
698 ptr[0] = 9;
699 ptr[1] = EIR_DEVICE_ID;
700
701 put_unaligned_le16(hdev->devid_source, ptr + 2);
702 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
703 put_unaligned_le16(hdev->devid_product, ptr + 6);
704 put_unaligned_le16(hdev->devid_version, ptr + 8);
705
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700706 ptr += 10;
707 }
708
Johan Hedberg213202e2013-01-27 00:31:33 +0200709 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200710 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200711 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300712}
713
Johan Hedberg890ea892013-03-15 17:06:52 -0500714static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300715{
Johan Hedberg890ea892013-03-15 17:06:52 -0500716 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300717 struct hci_cp_write_eir cp;
718
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200719 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500720 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200721
Johan Hedberg976eb202012-10-24 21:12:01 +0300722 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500723 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300724
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200725 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500726 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300727
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200728 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500729 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300730
731 memset(&cp, 0, sizeof(cp));
732
733 create_eir(hdev, cp.data);
734
735 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500736 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300737
738 memcpy(hdev->eir, cp.data, sizeof(cp.data));
739
Johan Hedberg890ea892013-03-15 17:06:52 -0500740 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300741}
742
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200743static u8 get_service_classes(struct hci_dev *hdev)
744{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300745 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200746 u8 val = 0;
747
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300748 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200749 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200750
751 return val;
752}
753
Johan Hedberg890ea892013-03-15 17:06:52 -0500754static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200755{
Johan Hedberg890ea892013-03-15 17:06:52 -0500756 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200757 u8 cod[3];
758
759 BT_DBG("%s", hdev->name);
760
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200761 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500762 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200763
Johan Hedbergf87ea1d2013-10-19 23:38:17 +0300764 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
765 return;
766
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200767 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500768 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200769
770 cod[0] = hdev->minor_class;
771 cod[1] = hdev->major_class;
772 cod[2] = get_service_classes(hdev);
773
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700774 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
775 cod[1] |= 0x20;
776
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200777 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500778 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200779
Johan Hedberg890ea892013-03-15 17:06:52 -0500780 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200781}
782
Johan Hedberg7d785252011-12-15 00:47:39 +0200783static void service_cache_off(struct work_struct *work)
784{
785 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300786 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500787 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200788
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200789 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200790 return;
791
Johan Hedberg890ea892013-03-15 17:06:52 -0500792 hci_req_init(&req, hdev);
793
Johan Hedberg7d785252011-12-15 00:47:39 +0200794 hci_dev_lock(hdev);
795
Johan Hedberg890ea892013-03-15 17:06:52 -0500796 update_eir(&req);
797 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200798
799 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500800
801 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200802}
803
Johan Hedberg6a919082012-02-28 06:17:26 +0200804static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200805{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200806 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200807 return;
808
Johan Hedberg4f87da82012-03-02 19:55:56 +0200809 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200810
Johan Hedberg4f87da82012-03-02 19:55:56 +0200811 /* Non-mgmt controlled devices get this bit set
812 * implicitly so that pairing works for them, however
813 * for mgmt we require user-space to explicitly enable
814 * it
815 */
816 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200817}
818
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200819static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300820 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200821{
822 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200823
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200824 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200825
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300826 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200827
Johan Hedberg03811012010-12-08 00:21:06 +0200828 memset(&rp, 0, sizeof(rp));
829
Johan Hedberg03811012010-12-08 00:21:06 +0200830 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200831
832 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200833 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200834
835 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
836 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
837
838 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200839
840 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200841 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200842
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300843 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200844
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200845 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300846 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200847}
848
849static void mgmt_pending_free(struct pending_cmd *cmd)
850{
851 sock_put(cmd->sk);
852 kfree(cmd->param);
853 kfree(cmd);
854}
855
856static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300857 struct hci_dev *hdev, void *data,
858 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200859{
860 struct pending_cmd *cmd;
861
Andre Guedes12b94562012-06-07 19:05:45 -0300862 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200863 if (!cmd)
864 return NULL;
865
866 cmd->opcode = opcode;
867 cmd->index = hdev->id;
868
Andre Guedes12b94562012-06-07 19:05:45 -0300869 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200870 if (!cmd->param) {
871 kfree(cmd);
872 return NULL;
873 }
874
875 if (data)
876 memcpy(cmd->param, data, len);
877
878 cmd->sk = sk;
879 sock_hold(sk);
880
881 list_add(&cmd->list, &hdev->mgmt_pending);
882
883 return cmd;
884}
885
886static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300887 void (*cb)(struct pending_cmd *cmd,
888 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300889 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200890{
Andre Guedesa3d09352013-02-01 11:21:30 -0300891 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200892
Andre Guedesa3d09352013-02-01 11:21:30 -0300893 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200894 if (opcode > 0 && cmd->opcode != opcode)
895 continue;
896
897 cb(cmd, data);
898 }
899}
900
Johan Hedberg03811012010-12-08 00:21:06 +0200901static void mgmt_pending_remove(struct pending_cmd *cmd)
902{
903 list_del(&cmd->list);
904 mgmt_pending_free(cmd);
905}
906
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200907static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200908{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200909 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200910
Johan Hedbergaee9b212012-02-18 15:07:59 +0200911 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300912 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200913}
914
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200915static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300916 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200917{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300918 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200919 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200920 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200921
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200922 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200923
Johan Hedberga7e80f22013-01-09 16:05:19 +0200924 if (cp->val != 0x00 && cp->val != 0x01)
925 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
926 MGMT_STATUS_INVALID_PARAMS);
927
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300928 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200929
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300930 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
931 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
932 MGMT_STATUS_BUSY);
933 goto failed;
934 }
935
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100936 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
937 cancel_delayed_work(&hdev->power_off);
938
939 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200940 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
941 data, len);
942 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100943 goto failed;
944 }
945 }
946
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200947 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200948 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200949 goto failed;
950 }
951
Johan Hedberg03811012010-12-08 00:21:06 +0200952 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
953 if (!cmd) {
954 err = -ENOMEM;
955 goto failed;
956 }
957
958 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200959 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200960 else
Johan Hedberg19202572013-01-14 22:33:51 +0200961 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200962
963 err = 0;
964
965failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300966 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200967 return err;
968}
969
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300970static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
971 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200972{
973 struct sk_buff *skb;
974 struct mgmt_hdr *hdr;
975
Andre Guedes790eff42012-06-07 19:05:46 -0300976 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200977 if (!skb)
978 return -ENOMEM;
979
980 hdr = (void *) skb_put(skb, sizeof(*hdr));
981 hdr->opcode = cpu_to_le16(event);
982 if (hdev)
983 hdr->index = cpu_to_le16(hdev->id);
984 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530985 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200986 hdr->len = cpu_to_le16(data_len);
987
988 if (data)
989 memcpy(skb_put(skb, data_len), data, data_len);
990
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100991 /* Time stamp */
992 __net_timestamp(skb);
993
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200994 hci_send_to_control(skb, skip_sk);
995 kfree_skb(skb);
996
997 return 0;
998}
999
1000static int new_settings(struct hci_dev *hdev, struct sock *skip)
1001{
1002 __le32 ev;
1003
1004 ev = cpu_to_le32(get_current_settings(hdev));
1005
1006 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1007}
1008
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001009struct cmd_lookup {
1010 struct sock *sk;
1011 struct hci_dev *hdev;
1012 u8 mgmt_status;
1013};
1014
1015static void settings_rsp(struct pending_cmd *cmd, void *data)
1016{
1017 struct cmd_lookup *match = data;
1018
1019 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1020
1021 list_del(&cmd->list);
1022
1023 if (match->sk == NULL) {
1024 match->sk = cmd->sk;
1025 sock_hold(match->sk);
1026 }
1027
1028 mgmt_pending_free(cmd);
1029}
1030
1031static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1032{
1033 u8 *status = data;
1034
1035 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1036 mgmt_pending_remove(cmd);
1037}
1038
Johan Hedberge6fe7982013-10-02 15:45:22 +03001039static u8 mgmt_bredr_support(struct hci_dev *hdev)
1040{
1041 if (!lmp_bredr_capable(hdev))
1042 return MGMT_STATUS_NOT_SUPPORTED;
1043 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1044 return MGMT_STATUS_REJECTED;
1045 else
1046 return MGMT_STATUS_SUCCESS;
1047}
1048
1049static u8 mgmt_le_support(struct hci_dev *hdev)
1050{
1051 if (!lmp_le_capable(hdev))
1052 return MGMT_STATUS_NOT_SUPPORTED;
1053 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1054 return MGMT_STATUS_REJECTED;
1055 else
1056 return MGMT_STATUS_SUCCESS;
1057}
1058
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001059static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1060{
1061 struct pending_cmd *cmd;
1062 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001063 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001064 bool changed;
1065
1066 BT_DBG("status 0x%02x", status);
1067
1068 hci_dev_lock(hdev);
1069
1070 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1071 if (!cmd)
1072 goto unlock;
1073
1074 if (status) {
1075 u8 mgmt_err = mgmt_status(status);
1076 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001077 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001078 goto remove_cmd;
1079 }
1080
1081 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001082 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001083 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1084 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001085
1086 if (hdev->discov_timeout > 0) {
1087 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1088 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1089 to);
1090 }
1091 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001092 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1093 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001094 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001095
1096 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1097
1098 if (changed)
1099 new_settings(hdev, cmd->sk);
1100
Marcel Holtmann970ba522013-10-15 06:33:57 -07001101 /* When the discoverable mode gets changed, make sure
1102 * that class of device has the limited discoverable
1103 * bit correctly set.
1104 */
1105 hci_req_init(&req, hdev);
1106 update_class(&req);
1107 hci_req_run(&req, NULL);
1108
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001109remove_cmd:
1110 mgmt_pending_remove(cmd);
1111
1112unlock:
1113 hci_dev_unlock(hdev);
1114}
1115
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001116static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001117 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001118{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001119 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001120 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001121 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001122 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001123 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001124 int err;
1125
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001126 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001127
Johan Hedberge6fe7982013-10-02 15:45:22 +03001128 status = mgmt_bredr_support(hdev);
1129 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001130 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001131 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001132
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001133 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga7e80f22013-01-09 16:05:19 +02001134 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1135 MGMT_STATUS_INVALID_PARAMS);
1136
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001137 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001138
1139 /* Disabling discoverable requires that no timeout is set,
1140 * and enabling limited discoverable requires a timeout.
1141 */
1142 if ((cp->val == 0x00 && timeout > 0) ||
1143 (cp->val == 0x02 && timeout == 0))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001144 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001145 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001146
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001147 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001148
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001149 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001150 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001151 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001152 goto failed;
1153 }
1154
1155 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001156 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001157 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001158 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001159 goto failed;
1160 }
1161
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001162 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001163 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001164 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001165 goto failed;
1166 }
1167
1168 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001169 bool changed = false;
1170
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001171 /* Setting limited discoverable when powered off is
1172 * not a valid operation since it requires a timeout
1173 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1174 */
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001175 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1176 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1177 changed = true;
1178 }
1179
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001180 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001181 if (err < 0)
1182 goto failed;
1183
1184 if (changed)
1185 err = new_settings(hdev, sk);
1186
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001187 goto failed;
1188 }
1189
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001190 /* If the current mode is the same, then just update the timeout
1191 * value with the new value. And if only the timeout gets updated,
1192 * then no need for any HCI transactions.
1193 */
1194 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) &&
1195 (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE,
1196 &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001197 cancel_delayed_work(&hdev->discov_off);
1198 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001199
Marcel Holtmann36261542013-10-15 08:28:51 -07001200 if (cp->val && hdev->discov_timeout > 0) {
1201 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001202 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001203 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001204 }
1205
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001206 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001207 goto failed;
1208 }
1209
1210 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1211 if (!cmd) {
1212 err = -ENOMEM;
1213 goto failed;
1214 }
1215
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001216 /* Cancel any potential discoverable timeout that might be
1217 * still active and store new timeout value. The arming of
1218 * the timeout happens in the complete handler.
1219 */
1220 cancel_delayed_work(&hdev->discov_off);
1221 hdev->discov_timeout = timeout;
1222
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001223 hci_req_init(&req, hdev);
1224
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001225 scan = SCAN_PAGE;
1226
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001227 if (cp->val) {
1228 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001229
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001230 if (cp->val == 0x02) {
1231 /* Limited discoverable mode */
1232 set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1233
1234 hci_cp.num_iac = 2;
1235 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1236 hci_cp.iac_lap[1] = 0x8b;
1237 hci_cp.iac_lap[2] = 0x9e;
1238 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1239 hci_cp.iac_lap[4] = 0x8b;
1240 hci_cp.iac_lap[5] = 0x9e;
1241 } else {
1242 /* General discoverable mode */
1243 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1244
1245 hci_cp.num_iac = 1;
1246 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1247 hci_cp.iac_lap[1] = 0x8b;
1248 hci_cp.iac_lap[2] = 0x9e;
1249 }
1250
1251 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1252 (hci_cp.num_iac * 3) + 1, &hci_cp);
1253
1254 scan |= SCAN_INQUIRY;
1255 } else {
1256 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1257 }
1258
1259 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001260
1261 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001262 if (err < 0)
1263 mgmt_pending_remove(cmd);
1264
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001265failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001266 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001267 return err;
1268}
1269
Johan Hedberg406d7802013-03-15 17:07:09 -05001270static void write_fast_connectable(struct hci_request *req, bool enable)
1271{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001272 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001273 struct hci_cp_write_page_scan_activity acp;
1274 u8 type;
1275
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001276 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1277 return;
1278
Johan Hedberg406d7802013-03-15 17:07:09 -05001279 if (enable) {
1280 type = PAGE_SCAN_TYPE_INTERLACED;
1281
1282 /* 160 msec page scan interval */
1283 acp.interval = __constant_cpu_to_le16(0x0100);
1284 } else {
1285 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1286
1287 /* default 1.28 sec page scan */
1288 acp.interval = __constant_cpu_to_le16(0x0800);
1289 }
1290
1291 acp.window = __constant_cpu_to_le16(0x0012);
1292
Johan Hedbergbd98b992013-03-15 17:07:13 -05001293 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1294 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1295 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1296 sizeof(acp), &acp);
1297
1298 if (hdev->page_scan_type != type)
1299 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001300}
1301
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001302static u8 get_adv_type(struct hci_dev *hdev)
1303{
1304 struct pending_cmd *cmd;
1305 bool connectable;
1306
1307 /* If there's a pending mgmt command the flag will not yet have
1308 * it's final value, so check for this first.
1309 */
1310 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1311 if (cmd) {
1312 struct mgmt_mode *cp = cmd->param;
1313 connectable = !!cp->val;
1314 } else {
1315 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1316 }
1317
1318 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1319}
1320
Johan Hedberg95c66e72013-10-14 16:20:06 +03001321static void enable_advertising(struct hci_request *req)
1322{
1323 struct hci_dev *hdev = req->hdev;
1324 struct hci_cp_le_set_adv_param cp;
1325 u8 enable = 0x01;
1326
1327 memset(&cp, 0, sizeof(cp));
1328 cp.min_interval = __constant_cpu_to_le16(0x0800);
1329 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001330 cp.type = get_adv_type(hdev);
Marcel Holtmann79830f62013-10-18 16:38:09 -07001331 cp.own_address_type = hdev->own_addr_type;
Johan Hedberg95c66e72013-10-14 16:20:06 +03001332 cp.channel_map = 0x07;
1333
1334 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1335
1336 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1337}
1338
1339static void disable_advertising(struct hci_request *req)
1340{
1341 u8 enable = 0x00;
1342
1343 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1344}
1345
Johan Hedberg2b76f452013-03-15 17:07:04 -05001346static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1347{
1348 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001349 struct mgmt_mode *cp;
1350 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001351
1352 BT_DBG("status 0x%02x", status);
1353
1354 hci_dev_lock(hdev);
1355
1356 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1357 if (!cmd)
1358 goto unlock;
1359
Johan Hedberg37438c12013-10-14 16:20:05 +03001360 if (status) {
1361 u8 mgmt_err = mgmt_status(status);
1362 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1363 goto remove_cmd;
1364 }
1365
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001366 cp = cmd->param;
1367 if (cp->val)
1368 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1369 else
1370 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1371
Johan Hedberg2b76f452013-03-15 17:07:04 -05001372 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1373
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001374 if (changed)
1375 new_settings(hdev, cmd->sk);
1376
Johan Hedberg37438c12013-10-14 16:20:05 +03001377remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001378 mgmt_pending_remove(cmd);
1379
1380unlock:
1381 hci_dev_unlock(hdev);
1382}
1383
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001384static int set_connectable_update_settings(struct hci_dev *hdev,
1385 struct sock *sk, u8 val)
1386{
1387 bool changed = false;
1388 int err;
1389
1390 if (!!val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1391 changed = true;
1392
1393 if (val) {
1394 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1395 } else {
1396 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1397 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1398 }
1399
1400 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1401 if (err < 0)
1402 return err;
1403
1404 if (changed)
1405 return new_settings(hdev, sk);
1406
1407 return 0;
1408}
1409
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001410static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001411 u16 len)
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001412{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001413 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001414 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001415 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001416 u8 scan;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001417 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001418
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001419 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001420
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001421 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1422 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001423 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001424 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001425
Johan Hedberga7e80f22013-01-09 16:05:19 +02001426 if (cp->val != 0x00 && cp->val != 0x01)
1427 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1428 MGMT_STATUS_INVALID_PARAMS);
1429
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001430 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001431
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001432 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001433 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001434 goto failed;
1435 }
1436
1437 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001438 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001439 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001440 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001441 goto failed;
1442 }
1443
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001444 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1445 if (!cmd) {
1446 err = -ENOMEM;
1447 goto failed;
1448 }
1449
Johan Hedberg2b76f452013-03-15 17:07:04 -05001450 hci_req_init(&req, hdev);
1451
Johan Hedberg9b742462013-10-14 16:20:03 +03001452 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) &&
1453 cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001454 if (cp->val) {
1455 scan = SCAN_PAGE;
1456 } else {
1457 scan = 0;
1458
1459 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001460 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001461 cancel_delayed_work(&hdev->discov_off);
1462 }
1463
1464 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1465 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001466
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001467 /* If we're going from non-connectable to connectable or
1468 * vice-versa when fast connectable is enabled ensure that fast
1469 * connectable gets disabled. write_fast_connectable won't do
1470 * anything if the page scan parameters are already what they
1471 * should be.
1472 */
1473 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001474 write_fast_connectable(&req, false);
1475
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001476 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1477 hci_conn_num(hdev, LE_LINK) == 0) {
1478 disable_advertising(&req);
1479 enable_advertising(&req);
1480 }
1481
Johan Hedberg2b76f452013-03-15 17:07:04 -05001482 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001483 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001484 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001485 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03001486 err = set_connectable_update_settings(hdev, sk,
1487 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03001488 goto failed;
1489 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001490
1491failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001492 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001493 return err;
1494}
1495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001496static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001497 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001498{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001499 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001500 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001501 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001502
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001503 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001504
Johan Hedberga7e80f22013-01-09 16:05:19 +02001505 if (cp->val != 0x00 && cp->val != 0x01)
1506 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1507 MGMT_STATUS_INVALID_PARAMS);
1508
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001509 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001510
1511 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001512 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001513 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001514 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001515
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001516 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001517 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001518 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001519
Marcel Holtmann55594352013-10-06 16:11:57 -07001520 if (changed)
1521 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001522
Marcel Holtmann55594352013-10-06 16:11:57 -07001523unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001524 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001525 return err;
1526}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001527
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001528static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1529 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001530{
1531 struct mgmt_mode *cp = data;
1532 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001533 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001534 int err;
1535
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001536 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001537
Johan Hedberge6fe7982013-10-02 15:45:22 +03001538 status = mgmt_bredr_support(hdev);
1539 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001540 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001541 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001542
Johan Hedberga7e80f22013-01-09 16:05:19 +02001543 if (cp->val != 0x00 && cp->val != 0x01)
1544 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1545 MGMT_STATUS_INVALID_PARAMS);
1546
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001547 hci_dev_lock(hdev);
1548
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001549 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001550 bool changed = false;
1551
1552 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001553 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001554 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1555 changed = true;
1556 }
1557
1558 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1559 if (err < 0)
1560 goto failed;
1561
1562 if (changed)
1563 err = new_settings(hdev, sk);
1564
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001565 goto failed;
1566 }
1567
1568 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001569 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001570 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001571 goto failed;
1572 }
1573
1574 val = !!cp->val;
1575
1576 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1577 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1578 goto failed;
1579 }
1580
1581 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1582 if (!cmd) {
1583 err = -ENOMEM;
1584 goto failed;
1585 }
1586
1587 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1588 if (err < 0) {
1589 mgmt_pending_remove(cmd);
1590 goto failed;
1591 }
1592
1593failed:
1594 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001595 return err;
1596}
1597
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001598static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001599{
1600 struct mgmt_mode *cp = data;
1601 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001602 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001603 int err;
1604
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001605 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001606
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001607 status = mgmt_bredr_support(hdev);
1608 if (status)
1609 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1610
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001611 if (!lmp_ssp_capable(hdev))
1612 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1613 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001614
Johan Hedberga7e80f22013-01-09 16:05:19 +02001615 if (cp->val != 0x00 && cp->val != 0x01)
1616 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1617 MGMT_STATUS_INVALID_PARAMS);
1618
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001619 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001620
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001621 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001622 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001623
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001624 if (cp->val) {
1625 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1626 &hdev->dev_flags);
1627 } else {
1628 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1629 &hdev->dev_flags);
1630 if (!changed)
1631 changed = test_and_clear_bit(HCI_HS_ENABLED,
1632 &hdev->dev_flags);
1633 else
1634 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001635 }
1636
1637 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1638 if (err < 0)
1639 goto failed;
1640
1641 if (changed)
1642 err = new_settings(hdev, sk);
1643
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001644 goto failed;
1645 }
1646
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001647 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1648 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001649 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1650 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001651 goto failed;
1652 }
1653
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001654 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001655 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1656 goto failed;
1657 }
1658
1659 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1660 if (!cmd) {
1661 err = -ENOMEM;
1662 goto failed;
1663 }
1664
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001665 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001666 if (err < 0) {
1667 mgmt_pending_remove(cmd);
1668 goto failed;
1669 }
1670
1671failed:
1672 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001673 return err;
1674}
1675
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001676static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001677{
1678 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001679 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001680 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001681 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001682
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001683 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001684
Johan Hedberge6fe7982013-10-02 15:45:22 +03001685 status = mgmt_bredr_support(hdev);
1686 if (status)
1687 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001688
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001689 if (!lmp_ssp_capable(hdev))
1690 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1691 MGMT_STATUS_NOT_SUPPORTED);
1692
1693 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1694 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1695 MGMT_STATUS_REJECTED);
1696
Johan Hedberga7e80f22013-01-09 16:05:19 +02001697 if (cp->val != 0x00 && cp->val != 0x01)
1698 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1699 MGMT_STATUS_INVALID_PARAMS);
1700
Marcel Holtmannee392692013-10-01 22:59:23 -07001701 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001702
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001703 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001704 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001705 } else {
1706 if (hdev_is_powered(hdev)) {
1707 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1708 MGMT_STATUS_REJECTED);
1709 goto unlock;
1710 }
1711
Marcel Holtmannee392692013-10-01 22:59:23 -07001712 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001713 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001714
1715 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1716 if (err < 0)
1717 goto unlock;
1718
1719 if (changed)
1720 err = new_settings(hdev, sk);
1721
1722unlock:
1723 hci_dev_unlock(hdev);
1724 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001725}
1726
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001727static void le_enable_complete(struct hci_dev *hdev, u8 status)
1728{
1729 struct cmd_lookup match = { NULL, hdev };
1730
1731 if (status) {
1732 u8 mgmt_err = mgmt_status(status);
1733
1734 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1735 &mgmt_err);
1736 return;
1737 }
1738
1739 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1740
1741 new_settings(hdev, match.sk);
1742
1743 if (match.sk)
1744 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001745
1746 /* Make sure the controller has a good default for
1747 * advertising data. Restrict the update to when LE
1748 * has actually been enabled. During power on, the
1749 * update in powered_update_hci will take care of it.
1750 */
1751 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1752 struct hci_request req;
1753
1754 hci_dev_lock(hdev);
1755
1756 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001757 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07001758 update_scan_rsp_data(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001759 hci_req_run(&req, NULL);
1760
1761 hci_dev_unlock(hdev);
1762 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001763}
1764
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001765static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001766{
1767 struct mgmt_mode *cp = data;
1768 struct hci_cp_write_le_host_supported hci_cp;
1769 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001770 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001771 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001772 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001773
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001774 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001775
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001776 if (!lmp_le_capable(hdev))
1777 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1778 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001779
Johan Hedberga7e80f22013-01-09 16:05:19 +02001780 if (cp->val != 0x00 && cp->val != 0x01)
1781 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1782 MGMT_STATUS_INVALID_PARAMS);
1783
Johan Hedbergc73eee92013-04-19 18:35:21 +03001784 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001785 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001786 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1787 MGMT_STATUS_REJECTED);
1788
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001789 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001790
1791 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001792 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001793
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001794 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001795 bool changed = false;
1796
1797 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1798 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1799 changed = true;
1800 }
1801
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001802 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1803 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001804 changed = true;
1805 }
1806
Johan Hedberg06199cf2012-02-22 16:37:11 +02001807 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1808 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001809 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001810
1811 if (changed)
1812 err = new_settings(hdev, sk);
1813
Johan Hedberg1de028c2012-02-29 19:55:35 -08001814 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001815 }
1816
Johan Hedberg4375f102013-09-25 13:26:10 +03001817 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1818 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001819 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001820 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001821 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001822 }
1823
1824 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1825 if (!cmd) {
1826 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001827 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001828 }
1829
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001830 hci_req_init(&req, hdev);
1831
Johan Hedberg06199cf2012-02-22 16:37:11 +02001832 memset(&hci_cp, 0, sizeof(hci_cp));
1833
1834 if (val) {
1835 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001836 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001837 } else {
1838 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1839 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001840 }
1841
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001842 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1843 &hci_cp);
1844
1845 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301846 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001847 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001848
Johan Hedberg1de028c2012-02-29 19:55:35 -08001849unlock:
1850 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001851 return err;
1852}
1853
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001854/* This is a helper function to test for pending mgmt commands that can
1855 * cause CoD or EIR HCI commands. We can only allow one such pending
1856 * mgmt command at a time since otherwise we cannot easily track what
1857 * the current values are, will be, and based on that calculate if a new
1858 * HCI command needs to be sent and if yes with what value.
1859 */
1860static bool pending_eir_or_class(struct hci_dev *hdev)
1861{
1862 struct pending_cmd *cmd;
1863
1864 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1865 switch (cmd->opcode) {
1866 case MGMT_OP_ADD_UUID:
1867 case MGMT_OP_REMOVE_UUID:
1868 case MGMT_OP_SET_DEV_CLASS:
1869 case MGMT_OP_SET_POWERED:
1870 return true;
1871 }
1872 }
1873
1874 return false;
1875}
1876
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001877static const u8 bluetooth_base_uuid[] = {
1878 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1879 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1880};
1881
1882static u8 get_uuid_size(const u8 *uuid)
1883{
1884 u32 val;
1885
1886 if (memcmp(uuid, bluetooth_base_uuid, 12))
1887 return 128;
1888
1889 val = get_unaligned_le32(&uuid[12]);
1890 if (val > 0xffff)
1891 return 32;
1892
1893 return 16;
1894}
1895
Johan Hedberg92da6092013-03-15 17:06:55 -05001896static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1897{
1898 struct pending_cmd *cmd;
1899
1900 hci_dev_lock(hdev);
1901
1902 cmd = mgmt_pending_find(mgmt_op, hdev);
1903 if (!cmd)
1904 goto unlock;
1905
1906 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1907 hdev->dev_class, 3);
1908
1909 mgmt_pending_remove(cmd);
1910
1911unlock:
1912 hci_dev_unlock(hdev);
1913}
1914
1915static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1916{
1917 BT_DBG("status 0x%02x", status);
1918
1919 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1920}
1921
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001922static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001923{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001924 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001925 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001926 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001927 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001928 int err;
1929
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001930 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001931
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001932 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001933
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001934 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001935 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001936 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001937 goto failed;
1938 }
1939
Andre Guedes92c4c202012-06-07 19:05:44 -03001940 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001941 if (!uuid) {
1942 err = -ENOMEM;
1943 goto failed;
1944 }
1945
1946 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001947 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001948 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001949
Johan Hedbergde66aa62013-01-27 00:31:27 +02001950 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001951
Johan Hedberg890ea892013-03-15 17:06:52 -05001952 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001953
Johan Hedberg890ea892013-03-15 17:06:52 -05001954 update_class(&req);
1955 update_eir(&req);
1956
Johan Hedberg92da6092013-03-15 17:06:55 -05001957 err = hci_req_run(&req, add_uuid_complete);
1958 if (err < 0) {
1959 if (err != -ENODATA)
1960 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001961
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001962 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001963 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001964 goto failed;
1965 }
1966
1967 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001968 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001969 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001970 goto failed;
1971 }
1972
1973 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001974
1975failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001976 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001977 return err;
1978}
1979
Johan Hedberg24b78d02012-02-23 23:24:30 +02001980static bool enable_service_cache(struct hci_dev *hdev)
1981{
1982 if (!hdev_is_powered(hdev))
1983 return false;
1984
1985 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001986 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1987 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001988 return true;
1989 }
1990
1991 return false;
1992}
1993
Johan Hedberg92da6092013-03-15 17:06:55 -05001994static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1995{
1996 BT_DBG("status 0x%02x", status);
1997
1998 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1999}
2000
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002001static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002002 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002003{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002004 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002005 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002006 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002007 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 -05002008 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002009 int err, found;
2010
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002011 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002012
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002013 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002014
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002015 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002016 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002017 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002018 goto unlock;
2019 }
2020
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002021 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
2022 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002023
Johan Hedberg24b78d02012-02-23 23:24:30 +02002024 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002025 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002026 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002027 goto unlock;
2028 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002029
Johan Hedberg9246a862012-02-23 21:33:16 +02002030 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002031 }
2032
2033 found = 0;
2034
Johan Hedberg056341c2013-01-27 00:31:30 +02002035 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002036 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2037 continue;
2038
2039 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002040 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002041 found++;
2042 }
2043
2044 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002045 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002046 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002047 goto unlock;
2048 }
2049
Johan Hedberg9246a862012-02-23 21:33:16 +02002050update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002051 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002052
Johan Hedberg890ea892013-03-15 17:06:52 -05002053 update_class(&req);
2054 update_eir(&req);
2055
Johan Hedberg92da6092013-03-15 17:06:55 -05002056 err = hci_req_run(&req, remove_uuid_complete);
2057 if (err < 0) {
2058 if (err != -ENODATA)
2059 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002060
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002061 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002062 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002063 goto unlock;
2064 }
2065
2066 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002067 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002068 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002069 goto unlock;
2070 }
2071
2072 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002073
2074unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002075 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002076 return err;
2077}
2078
Johan Hedberg92da6092013-03-15 17:06:55 -05002079static void set_class_complete(struct hci_dev *hdev, u8 status)
2080{
2081 BT_DBG("status 0x%02x", status);
2082
2083 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2084}
2085
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002086static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002087 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002088{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002089 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002090 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002091 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002092 int err;
2093
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002094 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002095
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002096 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002097 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2098 MGMT_STATUS_NOT_SUPPORTED);
2099
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002100 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002101
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002102 if (pending_eir_or_class(hdev)) {
2103 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2104 MGMT_STATUS_BUSY);
2105 goto unlock;
2106 }
2107
2108 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2109 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2110 MGMT_STATUS_INVALID_PARAMS);
2111 goto unlock;
2112 }
2113
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002114 hdev->major_class = cp->major;
2115 hdev->minor_class = cp->minor;
2116
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002117 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002118 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002119 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002120 goto unlock;
2121 }
2122
Johan Hedberg890ea892013-03-15 17:06:52 -05002123 hci_req_init(&req, hdev);
2124
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002125 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002126 hci_dev_unlock(hdev);
2127 cancel_delayed_work_sync(&hdev->service_cache);
2128 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002129 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002130 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002131
Johan Hedberg890ea892013-03-15 17:06:52 -05002132 update_class(&req);
2133
Johan Hedberg92da6092013-03-15 17:06:55 -05002134 err = hci_req_run(&req, set_class_complete);
2135 if (err < 0) {
2136 if (err != -ENODATA)
2137 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002138
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002139 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002140 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002141 goto unlock;
2142 }
2143
2144 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002145 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002146 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002147 goto unlock;
2148 }
2149
2150 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002151
Johan Hedbergb5235a62012-02-21 14:32:24 +02002152unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002153 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002154 return err;
2155}
2156
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002157static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002158 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002159{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002160 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002161 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002162 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002163
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002164 BT_DBG("request for %s", hdev->name);
2165
2166 if (!lmp_bredr_capable(hdev))
2167 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2168 MGMT_STATUS_NOT_SUPPORTED);
2169
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002170 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002171
Johan Hedberg86742e12011-11-07 23:13:38 +02002172 expected_len = sizeof(*cp) + key_count *
2173 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002174 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002175 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002176 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002177 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002178 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002179 }
2180
Johan Hedberg4ae14302013-01-20 14:27:13 +02002181 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2182 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2183 MGMT_STATUS_INVALID_PARAMS);
2184
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002185 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002186 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002187
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002188 for (i = 0; i < key_count; i++) {
2189 struct mgmt_link_key_info *key = &cp->keys[i];
2190
2191 if (key->addr.type != BDADDR_BREDR)
2192 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2193 MGMT_STATUS_INVALID_PARAMS);
2194 }
2195
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002196 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002197
2198 hci_link_keys_clear(hdev);
2199
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002200 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002201 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002202 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002203 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002204
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002205 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002206 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002207
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002208 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002209 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002210 }
2211
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002212 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002213
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002214 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002215
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002216 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002217}
2218
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002219static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002220 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002221{
2222 struct mgmt_ev_device_unpaired ev;
2223
2224 bacpy(&ev.addr.bdaddr, bdaddr);
2225 ev.addr.type = addr_type;
2226
2227 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002228 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002229}
2230
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002231static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002232 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002233{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002234 struct mgmt_cp_unpair_device *cp = data;
2235 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002236 struct hci_cp_disconnect dc;
2237 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002238 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002239 int err;
2240
Johan Hedberga8a1d192011-11-10 15:54:38 +02002241 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002242 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2243 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002244
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002245 if (!bdaddr_type_is_valid(cp->addr.type))
2246 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2247 MGMT_STATUS_INVALID_PARAMS,
2248 &rp, sizeof(rp));
2249
Johan Hedberg118da702013-01-20 14:27:20 +02002250 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2251 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2252 MGMT_STATUS_INVALID_PARAMS,
2253 &rp, sizeof(rp));
2254
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002255 hci_dev_lock(hdev);
2256
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002257 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002258 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002259 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002260 goto unlock;
2261 }
2262
Andre Guedes591f47f2012-04-24 21:02:49 -03002263 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02002264 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
2265 else
2266 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002267
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002268 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002269 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002270 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002271 goto unlock;
2272 }
2273
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002274 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002275 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002276 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002277 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002278 else
2279 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002280 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002281 } else {
2282 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002283 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002284
Johan Hedberga8a1d192011-11-10 15:54:38 +02002285 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002286 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002287 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002288 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002289 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002290 }
2291
Johan Hedberg124f6e32012-02-09 13:50:12 +02002292 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002293 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002294 if (!cmd) {
2295 err = -ENOMEM;
2296 goto unlock;
2297 }
2298
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002299 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002300 dc.reason = 0x13; /* Remote User Terminated Connection */
2301 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2302 if (err < 0)
2303 mgmt_pending_remove(cmd);
2304
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002305unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002306 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002307 return err;
2308}
2309
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002310static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002311 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002312{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002313 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002314 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002315 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002316 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002317 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002318 int err;
2319
2320 BT_DBG("");
2321
Johan Hedberg06a63b12013-01-20 14:27:21 +02002322 memset(&rp, 0, sizeof(rp));
2323 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2324 rp.addr.type = cp->addr.type;
2325
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002326 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002327 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2328 MGMT_STATUS_INVALID_PARAMS,
2329 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002330
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002331 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002332
2333 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002334 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2335 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002336 goto failed;
2337 }
2338
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002339 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002340 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2341 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002342 goto failed;
2343 }
2344
Andre Guedes591f47f2012-04-24 21:02:49 -03002345 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002346 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2347 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002348 else
2349 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002350
Vishal Agarwalf9607272012-06-13 05:32:43 +05302351 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002352 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2353 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002354 goto failed;
2355 }
2356
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002357 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002358 if (!cmd) {
2359 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002360 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002361 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002362
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002363 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002364 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002365
2366 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2367 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002368 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002369
2370failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002371 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002372 return err;
2373}
2374
Andre Guedes57c14772012-04-24 21:02:50 -03002375static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002376{
2377 switch (link_type) {
2378 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002379 switch (addr_type) {
2380 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002381 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002382
Johan Hedberg48264f02011-11-09 13:58:58 +02002383 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002384 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002385 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002386 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002387
Johan Hedberg4c659c32011-11-07 23:13:39 +02002388 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002389 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002390 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002391 }
2392}
2393
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002394static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2395 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002396{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002397 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002398 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002399 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002400 int err;
2401 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002402
2403 BT_DBG("");
2404
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002405 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002406
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002407 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002408 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002409 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002410 goto unlock;
2411 }
2412
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002413 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002414 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2415 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002416 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002417 }
2418
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002419 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002420 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002421 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002422 err = -ENOMEM;
2423 goto unlock;
2424 }
2425
Johan Hedberg2784eb42011-01-21 13:56:35 +02002426 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002427 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002428 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2429 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002430 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002431 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002432 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002433 continue;
2434 i++;
2435 }
2436
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002437 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002438
Johan Hedberg4c659c32011-11-07 23:13:39 +02002439 /* Recalculate length in case of filtered SCO connections, etc */
2440 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002441
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002442 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002443 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002444
Johan Hedberga38528f2011-01-22 06:46:43 +02002445 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002446
2447unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002448 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002449 return err;
2450}
2451
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002452static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002453 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002454{
2455 struct pending_cmd *cmd;
2456 int err;
2457
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002458 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002459 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002460 if (!cmd)
2461 return -ENOMEM;
2462
Johan Hedbergd8457692012-02-17 14:24:57 +02002463 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002464 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002465 if (err < 0)
2466 mgmt_pending_remove(cmd);
2467
2468 return err;
2469}
2470
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002471static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002472 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002473{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002474 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002475 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002476 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002477 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002478 int err;
2479
2480 BT_DBG("");
2481
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002482 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002483
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002484 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002485 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002486 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002487 goto failed;
2488 }
2489
Johan Hedbergd8457692012-02-17 14:24:57 +02002490 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002491 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002492 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002493 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002494 goto failed;
2495 }
2496
2497 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002498 struct mgmt_cp_pin_code_neg_reply ncp;
2499
2500 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002501
2502 BT_ERR("PIN code is not 16 bytes long");
2503
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002504 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002505 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002506 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002507 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002508
2509 goto failed;
2510 }
2511
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002512 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002513 if (!cmd) {
2514 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002515 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002516 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002517
Johan Hedbergd8457692012-02-17 14:24:57 +02002518 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002519 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002520 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002521
2522 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2523 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002524 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002525
2526failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002527 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002528 return err;
2529}
2530
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002531static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2532 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002533{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002534 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002535
2536 BT_DBG("");
2537
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002538 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002539
2540 hdev->io_capability = cp->io_capability;
2541
2542 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002543 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002544
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002545 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002546
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002547 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2548 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002549}
2550
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002551static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002552{
2553 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002554 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002555
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002556 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002557 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2558 continue;
2559
Johan Hedberge9a416b2011-02-19 12:05:56 -03002560 if (cmd->user_data != conn)
2561 continue;
2562
2563 return cmd;
2564 }
2565
2566 return NULL;
2567}
2568
2569static void pairing_complete(struct pending_cmd *cmd, u8 status)
2570{
2571 struct mgmt_rp_pair_device rp;
2572 struct hci_conn *conn = cmd->user_data;
2573
Johan Hedbergba4e5642011-11-11 00:07:34 +02002574 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002575 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002576
Johan Hedbergaee9b212012-02-18 15:07:59 +02002577 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002578 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002579
2580 /* So we don't get further callbacks for this connection */
2581 conn->connect_cfm_cb = NULL;
2582 conn->security_cfm_cb = NULL;
2583 conn->disconn_cfm_cb = NULL;
2584
David Herrmann76a68ba2013-04-06 20:28:37 +02002585 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002586
Johan Hedberga664b5b2011-02-19 12:06:02 -03002587 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002588}
2589
2590static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2591{
2592 struct pending_cmd *cmd;
2593
2594 BT_DBG("status %u", status);
2595
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002596 cmd = find_pairing(conn);
2597 if (!cmd)
2598 BT_DBG("Unable to find a pending command");
2599 else
Johan Hedberge2113262012-02-18 15:20:03 +02002600 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002601}
2602
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302603static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2604{
2605 struct pending_cmd *cmd;
2606
2607 BT_DBG("status %u", status);
2608
2609 if (!status)
2610 return;
2611
2612 cmd = find_pairing(conn);
2613 if (!cmd)
2614 BT_DBG("Unable to find a pending command");
2615 else
2616 pairing_complete(cmd, mgmt_status(status));
2617}
2618
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002619static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002620 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002621{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002622 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002623 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002624 struct pending_cmd *cmd;
2625 u8 sec_level, auth_type;
2626 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002627 int err;
2628
2629 BT_DBG("");
2630
Szymon Jancf950a30e2013-01-18 12:48:07 +01002631 memset(&rp, 0, sizeof(rp));
2632 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2633 rp.addr.type = cp->addr.type;
2634
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002635 if (!bdaddr_type_is_valid(cp->addr.type))
2636 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2637 MGMT_STATUS_INVALID_PARAMS,
2638 &rp, sizeof(rp));
2639
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002640 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002641
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002642 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002643 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2644 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002645 goto unlock;
2646 }
2647
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002648 sec_level = BT_SECURITY_MEDIUM;
2649 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002650 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002651 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002652 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002653
Andre Guedes591f47f2012-04-24 21:02:49 -03002654 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002655 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2656 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002657 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002658 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2659 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002660
Ville Tervo30e76272011-02-22 16:10:53 -03002661 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002662 int status;
2663
2664 if (PTR_ERR(conn) == -EBUSY)
2665 status = MGMT_STATUS_BUSY;
2666 else
2667 status = MGMT_STATUS_CONNECT_FAILED;
2668
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002669 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002670 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002671 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002672 goto unlock;
2673 }
2674
2675 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002676 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002677 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002678 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002679 goto unlock;
2680 }
2681
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002682 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002683 if (!cmd) {
2684 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002685 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002686 goto unlock;
2687 }
2688
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002689 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002690 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002691 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302692 else
2693 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002694
Johan Hedberge9a416b2011-02-19 12:05:56 -03002695 conn->security_cfm_cb = pairing_complete_cb;
2696 conn->disconn_cfm_cb = pairing_complete_cb;
2697 conn->io_capability = cp->io_cap;
2698 cmd->user_data = conn;
2699
2700 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002701 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002702 pairing_complete(cmd, 0);
2703
2704 err = 0;
2705
2706unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002707 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002708 return err;
2709}
2710
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002711static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2712 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002713{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002714 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002715 struct pending_cmd *cmd;
2716 struct hci_conn *conn;
2717 int err;
2718
2719 BT_DBG("");
2720
Johan Hedberg28424702012-02-02 04:02:29 +02002721 hci_dev_lock(hdev);
2722
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002723 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002724 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002725 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002726 goto unlock;
2727 }
2728
Johan Hedberg28424702012-02-02 04:02:29 +02002729 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2730 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002731 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002732 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002733 goto unlock;
2734 }
2735
2736 conn = cmd->user_data;
2737
2738 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002739 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002740 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002741 goto unlock;
2742 }
2743
2744 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2745
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002746 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002747 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002748unlock:
2749 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002750 return err;
2751}
2752
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002753static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002754 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002755 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002756{
Johan Hedberga5c29682011-02-19 12:05:57 -03002757 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002758 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002759 int err;
2760
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002761 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002762
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002763 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002764 err = cmd_complete(sk, hdev->id, mgmt_op,
2765 MGMT_STATUS_NOT_POWERED, addr,
2766 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002767 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002768 }
2769
Johan Hedberg1707c602013-03-15 17:07:15 -05002770 if (addr->type == BDADDR_BREDR)
2771 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002772 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002773 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002774
Johan Hedberg272d90d2012-02-09 15:26:12 +02002775 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002776 err = cmd_complete(sk, hdev->id, mgmt_op,
2777 MGMT_STATUS_NOT_CONNECTED, addr,
2778 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002779 goto done;
2780 }
2781
Johan Hedberg1707c602013-03-15 17:07:15 -05002782 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002783 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002784 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002785
Brian Gix5fe57d92011-12-21 16:12:13 -08002786 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002787 err = cmd_complete(sk, hdev->id, mgmt_op,
2788 MGMT_STATUS_SUCCESS, addr,
2789 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002790 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002791 err = cmd_complete(sk, hdev->id, mgmt_op,
2792 MGMT_STATUS_FAILED, addr,
2793 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002794
Brian Gix47c15e22011-11-16 13:53:14 -08002795 goto done;
2796 }
2797
Johan Hedberg1707c602013-03-15 17:07:15 -05002798 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002799 if (!cmd) {
2800 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002801 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002802 }
2803
Brian Gix0df4c182011-11-16 13:53:13 -08002804 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002805 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2806 struct hci_cp_user_passkey_reply cp;
2807
Johan Hedberg1707c602013-03-15 17:07:15 -05002808 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002809 cp.passkey = passkey;
2810 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2811 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002812 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2813 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002814
Johan Hedberga664b5b2011-02-19 12:06:02 -03002815 if (err < 0)
2816 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002817
Brian Gix0df4c182011-11-16 13:53:13 -08002818done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002819 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002820 return err;
2821}
2822
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302823static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2824 void *data, u16 len)
2825{
2826 struct mgmt_cp_pin_code_neg_reply *cp = data;
2827
2828 BT_DBG("");
2829
Johan Hedberg1707c602013-03-15 17:07:15 -05002830 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302831 MGMT_OP_PIN_CODE_NEG_REPLY,
2832 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2833}
2834
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002835static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2836 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002837{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002838 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002839
2840 BT_DBG("");
2841
2842 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002843 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002844 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002845
Johan Hedberg1707c602013-03-15 17:07:15 -05002846 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002847 MGMT_OP_USER_CONFIRM_REPLY,
2848 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002849}
2850
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002851static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002852 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002853{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002854 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002855
2856 BT_DBG("");
2857
Johan Hedberg1707c602013-03-15 17:07:15 -05002858 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002859 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2860 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002861}
2862
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002863static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2864 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002865{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002866 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002867
2868 BT_DBG("");
2869
Johan Hedberg1707c602013-03-15 17:07:15 -05002870 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002871 MGMT_OP_USER_PASSKEY_REPLY,
2872 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002873}
2874
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002875static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002876 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002877{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002878 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002879
2880 BT_DBG("");
2881
Johan Hedberg1707c602013-03-15 17:07:15 -05002882 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002883 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2884 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002885}
2886
Johan Hedberg13928972013-03-15 17:07:00 -05002887static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002888{
Johan Hedberg13928972013-03-15 17:07:00 -05002889 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002890 struct hci_cp_write_local_name cp;
2891
Johan Hedberg13928972013-03-15 17:07:00 -05002892 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002893
Johan Hedberg890ea892013-03-15 17:06:52 -05002894 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002895}
2896
Johan Hedberg13928972013-03-15 17:07:00 -05002897static void set_name_complete(struct hci_dev *hdev, u8 status)
2898{
2899 struct mgmt_cp_set_local_name *cp;
2900 struct pending_cmd *cmd;
2901
2902 BT_DBG("status 0x%02x", status);
2903
2904 hci_dev_lock(hdev);
2905
2906 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2907 if (!cmd)
2908 goto unlock;
2909
2910 cp = cmd->param;
2911
2912 if (status)
2913 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2914 mgmt_status(status));
2915 else
2916 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2917 cp, sizeof(*cp));
2918
2919 mgmt_pending_remove(cmd);
2920
2921unlock:
2922 hci_dev_unlock(hdev);
2923}
2924
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002925static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002926 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002927{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002928 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002929 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002930 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002931 int err;
2932
2933 BT_DBG("");
2934
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002935 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002936
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002937 /* If the old values are the same as the new ones just return a
2938 * direct command complete event.
2939 */
2940 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2941 !memcmp(hdev->short_name, cp->short_name,
2942 sizeof(hdev->short_name))) {
2943 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2944 data, len);
2945 goto failed;
2946 }
2947
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002948 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002949
Johan Hedbergb5235a62012-02-21 14:32:24 +02002950 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002951 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002952
2953 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002954 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002955 if (err < 0)
2956 goto failed;
2957
2958 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002959 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002960
Johan Hedbergb5235a62012-02-21 14:32:24 +02002961 goto failed;
2962 }
2963
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002964 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002965 if (!cmd) {
2966 err = -ENOMEM;
2967 goto failed;
2968 }
2969
Johan Hedberg13928972013-03-15 17:07:00 -05002970 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2971
Johan Hedberg890ea892013-03-15 17:06:52 -05002972 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002973
2974 if (lmp_bredr_capable(hdev)) {
2975 update_name(&req);
2976 update_eir(&req);
2977 }
2978
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07002979 /* The name is stored in the scan response data and so
2980 * no need to udpate the advertising data here.
2981 */
Johan Hedberg3f985052013-03-15 17:07:02 -05002982 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07002983 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05002984
Johan Hedberg13928972013-03-15 17:07:00 -05002985 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002986 if (err < 0)
2987 mgmt_pending_remove(cmd);
2988
2989failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002990 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002991 return err;
2992}
2993
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002994static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002995 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002996{
Szymon Jancc35938b2011-03-22 13:12:21 +01002997 struct pending_cmd *cmd;
2998 int err;
2999
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003000 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003001
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003002 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003003
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003004 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003005 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003006 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003007 goto unlock;
3008 }
3009
Andre Guedes9a1a1992012-07-24 15:03:48 -03003010 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003011 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003012 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003013 goto unlock;
3014 }
3015
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003016 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003017 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003018 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003019 goto unlock;
3020 }
3021
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003022 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003023 if (!cmd) {
3024 err = -ENOMEM;
3025 goto unlock;
3026 }
3027
3028 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3029 if (err < 0)
3030 mgmt_pending_remove(cmd);
3031
3032unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003033 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003034 return err;
3035}
3036
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003037static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003038 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003039{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003040 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003041 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003042 int err;
3043
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003044 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003045
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003046 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003047
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003048 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003049 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01003050 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003051 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01003052 else
Szymon Janca6785be2012-12-13 15:11:21 +01003053 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003054
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003055 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003056 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003057
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003058 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003059 return err;
3060}
3061
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003062static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003063 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003064{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003065 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003066 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003067 int err;
3068
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003069 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003070
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003071 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003072
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003073 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003074 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003075 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003076 else
Szymon Janca6785be2012-12-13 15:11:21 +01003077 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003078
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003079 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003080 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003081
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003082 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003083 return err;
3084}
3085
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003086static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3087{
3088 struct pending_cmd *cmd;
3089 u8 type;
3090 int err;
3091
3092 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3093
3094 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3095 if (!cmd)
3096 return -ENOENT;
3097
3098 type = hdev->discovery.type;
3099
3100 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3101 &type, sizeof(type));
3102 mgmt_pending_remove(cmd);
3103
3104 return err;
3105}
3106
Andre Guedes7c307722013-04-30 15:29:28 -03003107static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3108{
3109 BT_DBG("status %d", status);
3110
3111 if (status) {
3112 hci_dev_lock(hdev);
3113 mgmt_start_discovery_failed(hdev, status);
3114 hci_dev_unlock(hdev);
3115 return;
3116 }
3117
3118 hci_dev_lock(hdev);
3119 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3120 hci_dev_unlock(hdev);
3121
3122 switch (hdev->discovery.type) {
3123 case DISCOV_TYPE_LE:
3124 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003125 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003126 break;
3127
3128 case DISCOV_TYPE_INTERLEAVED:
3129 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003130 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003131 break;
3132
3133 case DISCOV_TYPE_BREDR:
3134 break;
3135
3136 default:
3137 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3138 }
3139}
3140
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003141static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003142 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003143{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003144 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003145 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003146 struct hci_cp_le_set_scan_param param_cp;
3147 struct hci_cp_le_set_scan_enable enable_cp;
3148 struct hci_cp_inquiry inq_cp;
3149 struct hci_request req;
3150 /* General inquiry access code (GIAC) */
3151 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003152 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003153 int err;
3154
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003155 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003156
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003157 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003158
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003159 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003160 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003161 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003162 goto failed;
3163 }
3164
Andre Guedes642be6c2012-03-21 00:03:37 -03003165 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3166 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3167 MGMT_STATUS_BUSY);
3168 goto failed;
3169 }
3170
Johan Hedbergff9ef572012-01-04 14:23:45 +02003171 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003172 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003173 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003174 goto failed;
3175 }
3176
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003177 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003178 if (!cmd) {
3179 err = -ENOMEM;
3180 goto failed;
3181 }
3182
Andre Guedes4aab14e2012-02-17 20:39:36 -03003183 hdev->discovery.type = cp->type;
3184
Andre Guedes7c307722013-04-30 15:29:28 -03003185 hci_req_init(&req, hdev);
3186
Andre Guedes4aab14e2012-02-17 20:39:36 -03003187 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003188 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003189 status = mgmt_bredr_support(hdev);
3190 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003191 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003192 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003193 mgmt_pending_remove(cmd);
3194 goto failed;
3195 }
3196
Andre Guedes7c307722013-04-30 15:29:28 -03003197 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3198 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3199 MGMT_STATUS_BUSY);
3200 mgmt_pending_remove(cmd);
3201 goto failed;
3202 }
3203
3204 hci_inquiry_cache_flush(hdev);
3205
3206 memset(&inq_cp, 0, sizeof(inq_cp));
3207 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003208 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003209 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003210 break;
3211
3212 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003213 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003214 status = mgmt_le_support(hdev);
3215 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003216 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003217 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003218 mgmt_pending_remove(cmd);
3219 goto failed;
3220 }
3221
Andre Guedes7c307722013-04-30 15:29:28 -03003222 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003223 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003224 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3225 MGMT_STATUS_NOT_SUPPORTED);
3226 mgmt_pending_remove(cmd);
3227 goto failed;
3228 }
3229
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003230 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003231 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3232 MGMT_STATUS_REJECTED);
3233 mgmt_pending_remove(cmd);
3234 goto failed;
3235 }
3236
3237 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3238 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3239 MGMT_STATUS_BUSY);
3240 mgmt_pending_remove(cmd);
3241 goto failed;
3242 }
3243
3244 memset(&param_cp, 0, sizeof(param_cp));
3245 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003246 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3247 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmann79830f62013-10-18 16:38:09 -07003248 param_cp.own_address_type = hdev->own_addr_type;
Andre Guedes7c307722013-04-30 15:29:28 -03003249 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3250 &param_cp);
3251
3252 memset(&enable_cp, 0, sizeof(enable_cp));
3253 enable_cp.enable = LE_SCAN_ENABLE;
3254 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3255 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3256 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003257 break;
3258
Andre Guedesf39799f2012-02-17 20:39:35 -03003259 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003260 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3261 MGMT_STATUS_INVALID_PARAMS);
3262 mgmt_pending_remove(cmd);
3263 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003264 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003265
Andre Guedes7c307722013-04-30 15:29:28 -03003266 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003267 if (err < 0)
3268 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003269 else
3270 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003271
3272failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003273 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003274 return err;
3275}
3276
Andre Guedes1183fdc2013-04-30 15:29:35 -03003277static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3278{
3279 struct pending_cmd *cmd;
3280 int err;
3281
3282 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3283 if (!cmd)
3284 return -ENOENT;
3285
3286 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3287 &hdev->discovery.type, sizeof(hdev->discovery.type));
3288 mgmt_pending_remove(cmd);
3289
3290 return err;
3291}
3292
Andre Guedes0e05bba2013-04-30 15:29:33 -03003293static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3294{
3295 BT_DBG("status %d", status);
3296
3297 hci_dev_lock(hdev);
3298
3299 if (status) {
3300 mgmt_stop_discovery_failed(hdev, status);
3301 goto unlock;
3302 }
3303
3304 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3305
3306unlock:
3307 hci_dev_unlock(hdev);
3308}
3309
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003310static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003311 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003312{
Johan Hedbergd9306502012-02-20 23:25:18 +02003313 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003314 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003315 struct hci_cp_remote_name_req_cancel cp;
3316 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003317 struct hci_request req;
3318 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003319 int err;
3320
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003321 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003322
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003323 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003324
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003325 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003326 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003327 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3328 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003329 goto unlock;
3330 }
3331
3332 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003333 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003334 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3335 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003336 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003337 }
3338
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003339 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003340 if (!cmd) {
3341 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003342 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003343 }
3344
Andre Guedes0e05bba2013-04-30 15:29:33 -03003345 hci_req_init(&req, hdev);
3346
Andre Guedese0d9727e2012-03-20 15:15:36 -03003347 switch (hdev->discovery.state) {
3348 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003349 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3350 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3351 } else {
3352 cancel_delayed_work(&hdev->le_scan_disable);
3353
3354 memset(&enable_cp, 0, sizeof(enable_cp));
3355 enable_cp.enable = LE_SCAN_DISABLE;
3356 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3357 sizeof(enable_cp), &enable_cp);
3358 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003359
Andre Guedese0d9727e2012-03-20 15:15:36 -03003360 break;
3361
3362 case DISCOVERY_RESOLVING:
3363 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003364 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003365 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003366 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003367 err = cmd_complete(sk, hdev->id,
3368 MGMT_OP_STOP_DISCOVERY, 0,
3369 &mgmt_cp->type,
3370 sizeof(mgmt_cp->type));
3371 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3372 goto unlock;
3373 }
3374
3375 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003376 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3377 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003378
3379 break;
3380
3381 default:
3382 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003383
3384 mgmt_pending_remove(cmd);
3385 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3386 MGMT_STATUS_FAILED, &mgmt_cp->type,
3387 sizeof(mgmt_cp->type));
3388 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003389 }
3390
Andre Guedes0e05bba2013-04-30 15:29:33 -03003391 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003392 if (err < 0)
3393 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003394 else
3395 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003396
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003397unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003398 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003399 return err;
3400}
3401
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003402static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003403 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003404{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003405 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003406 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003407 int err;
3408
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003409 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003410
Johan Hedberg561aafb2012-01-04 13:31:59 +02003411 hci_dev_lock(hdev);
3412
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003413 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003414 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003415 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003416 goto failed;
3417 }
3418
Johan Hedberga198e7b2012-02-17 14:27:06 +02003419 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003420 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003421 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003422 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003423 goto failed;
3424 }
3425
3426 if (cp->name_known) {
3427 e->name_state = NAME_KNOWN;
3428 list_del(&e->list);
3429 } else {
3430 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003431 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003432 }
3433
Johan Hedberge3846622013-01-09 15:29:33 +02003434 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3435 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003436
3437failed:
3438 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003439 return err;
3440}
3441
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003442static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003443 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003444{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003445 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003446 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003447 int err;
3448
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003449 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003450
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003451 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003452 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3453 MGMT_STATUS_INVALID_PARAMS,
3454 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003455
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003456 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003457
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003458 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003459 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003460 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003461 else
Szymon Janca6785be2012-12-13 15:11:21 +01003462 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003463
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003464 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003465 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003466
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003467 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003468
3469 return err;
3470}
3471
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003472static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003473 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003474{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003475 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003476 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003477 int err;
3478
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003479 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003480
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003481 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003482 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3483 MGMT_STATUS_INVALID_PARAMS,
3484 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003485
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003486 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003487
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003488 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003489 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003490 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003491 else
Szymon Janca6785be2012-12-13 15:11:21 +01003492 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003493
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003494 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003495 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003496
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003497 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003498
3499 return err;
3500}
3501
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003502static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3503 u16 len)
3504{
3505 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003506 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003507 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003508 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003509
3510 BT_DBG("%s", hdev->name);
3511
Szymon Jancc72d4b82012-03-16 16:02:57 +01003512 source = __le16_to_cpu(cp->source);
3513
3514 if (source > 0x0002)
3515 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3516 MGMT_STATUS_INVALID_PARAMS);
3517
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003518 hci_dev_lock(hdev);
3519
Szymon Jancc72d4b82012-03-16 16:02:57 +01003520 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003521 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3522 hdev->devid_product = __le16_to_cpu(cp->product);
3523 hdev->devid_version = __le16_to_cpu(cp->version);
3524
3525 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3526
Johan Hedberg890ea892013-03-15 17:06:52 -05003527 hci_req_init(&req, hdev);
3528 update_eir(&req);
3529 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003530
3531 hci_dev_unlock(hdev);
3532
3533 return err;
3534}
3535
Johan Hedberg4375f102013-09-25 13:26:10 +03003536static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3537{
3538 struct cmd_lookup match = { NULL, hdev };
3539
3540 if (status) {
3541 u8 mgmt_err = mgmt_status(status);
3542
3543 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3544 cmd_status_rsp, &mgmt_err);
3545 return;
3546 }
3547
3548 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3549 &match);
3550
3551 new_settings(hdev, match.sk);
3552
3553 if (match.sk)
3554 sock_put(match.sk);
3555}
3556
Marcel Holtmann21b51872013-10-10 09:47:53 -07003557static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3558 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003559{
3560 struct mgmt_mode *cp = data;
3561 struct pending_cmd *cmd;
3562 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003563 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003564 int err;
3565
3566 BT_DBG("request for %s", hdev->name);
3567
Johan Hedberge6fe7982013-10-02 15:45:22 +03003568 status = mgmt_le_support(hdev);
3569 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003570 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003571 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003572
3573 if (cp->val != 0x00 && cp->val != 0x01)
3574 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3575 MGMT_STATUS_INVALID_PARAMS);
3576
3577 hci_dev_lock(hdev);
3578
3579 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003580 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003581
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003582 /* The following conditions are ones which mean that we should
3583 * not do any HCI communication but directly send a mgmt
3584 * response to user space (after toggling the flag if
3585 * necessary).
3586 */
3587 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003588 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003589 bool changed = false;
3590
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003591 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3592 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003593 changed = true;
3594 }
3595
3596 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3597 if (err < 0)
3598 goto unlock;
3599
3600 if (changed)
3601 err = new_settings(hdev, sk);
3602
3603 goto unlock;
3604 }
3605
3606 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3607 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3608 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3609 MGMT_STATUS_BUSY);
3610 goto unlock;
3611 }
3612
3613 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3614 if (!cmd) {
3615 err = -ENOMEM;
3616 goto unlock;
3617 }
3618
3619 hci_req_init(&req, hdev);
3620
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003621 if (val)
3622 enable_advertising(&req);
3623 else
3624 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003625
3626 err = hci_req_run(&req, set_advertising_complete);
3627 if (err < 0)
3628 mgmt_pending_remove(cmd);
3629
3630unlock:
3631 hci_dev_unlock(hdev);
3632 return err;
3633}
3634
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003635static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3636 void *data, u16 len)
3637{
3638 struct mgmt_cp_set_static_address *cp = data;
3639 int err;
3640
3641 BT_DBG("%s", hdev->name);
3642
Marcel Holtmann62af4442013-10-02 22:10:32 -07003643 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003644 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003645 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003646
3647 if (hdev_is_powered(hdev))
3648 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3649 MGMT_STATUS_REJECTED);
3650
3651 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3652 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3653 return cmd_status(sk, hdev->id,
3654 MGMT_OP_SET_STATIC_ADDRESS,
3655 MGMT_STATUS_INVALID_PARAMS);
3656
3657 /* Two most significant bits shall be set */
3658 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3659 return cmd_status(sk, hdev->id,
3660 MGMT_OP_SET_STATIC_ADDRESS,
3661 MGMT_STATUS_INVALID_PARAMS);
3662 }
3663
3664 hci_dev_lock(hdev);
3665
3666 bacpy(&hdev->static_addr, &cp->bdaddr);
3667
3668 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3669
3670 hci_dev_unlock(hdev);
3671
3672 return err;
3673}
3674
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003675static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3676 void *data, u16 len)
3677{
3678 struct mgmt_cp_set_scan_params *cp = data;
3679 __u16 interval, window;
3680 int err;
3681
3682 BT_DBG("%s", hdev->name);
3683
3684 if (!lmp_le_capable(hdev))
3685 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3686 MGMT_STATUS_NOT_SUPPORTED);
3687
3688 interval = __le16_to_cpu(cp->interval);
3689
3690 if (interval < 0x0004 || interval > 0x4000)
3691 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3692 MGMT_STATUS_INVALID_PARAMS);
3693
3694 window = __le16_to_cpu(cp->window);
3695
3696 if (window < 0x0004 || window > 0x4000)
3697 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3698 MGMT_STATUS_INVALID_PARAMS);
3699
Marcel Holtmann899e1072013-10-14 09:55:32 -07003700 if (window > interval)
3701 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3702 MGMT_STATUS_INVALID_PARAMS);
3703
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003704 hci_dev_lock(hdev);
3705
3706 hdev->le_scan_interval = interval;
3707 hdev->le_scan_window = window;
3708
3709 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3710
3711 hci_dev_unlock(hdev);
3712
3713 return err;
3714}
3715
Johan Hedberg33e38b32013-03-15 17:07:05 -05003716static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3717{
3718 struct pending_cmd *cmd;
3719
3720 BT_DBG("status 0x%02x", status);
3721
3722 hci_dev_lock(hdev);
3723
3724 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3725 if (!cmd)
3726 goto unlock;
3727
3728 if (status) {
3729 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3730 mgmt_status(status));
3731 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003732 struct mgmt_mode *cp = cmd->param;
3733
3734 if (cp->val)
3735 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3736 else
3737 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3738
Johan Hedberg33e38b32013-03-15 17:07:05 -05003739 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3740 new_settings(hdev, cmd->sk);
3741 }
3742
3743 mgmt_pending_remove(cmd);
3744
3745unlock:
3746 hci_dev_unlock(hdev);
3747}
3748
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003749static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003750 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003751{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003752 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003753 struct pending_cmd *cmd;
3754 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003755 int err;
3756
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003757 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003758
Johan Hedberg56f87902013-10-02 13:43:13 +03003759 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3760 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003761 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3762 MGMT_STATUS_NOT_SUPPORTED);
3763
Johan Hedberga7e80f22013-01-09 16:05:19 +02003764 if (cp->val != 0x00 && cp->val != 0x01)
3765 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3766 MGMT_STATUS_INVALID_PARAMS);
3767
Johan Hedberg5400c042012-02-21 16:40:33 +02003768 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003769 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003770 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003771
3772 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003773 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003774 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003775
3776 hci_dev_lock(hdev);
3777
Johan Hedberg05cbf292013-03-15 17:07:07 -05003778 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3779 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3780 MGMT_STATUS_BUSY);
3781 goto unlock;
3782 }
3783
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003784 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3785 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3786 hdev);
3787 goto unlock;
3788 }
3789
Johan Hedberg33e38b32013-03-15 17:07:05 -05003790 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3791 data, len);
3792 if (!cmd) {
3793 err = -ENOMEM;
3794 goto unlock;
3795 }
3796
3797 hci_req_init(&req, hdev);
3798
Johan Hedberg406d7802013-03-15 17:07:09 -05003799 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003800
3801 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003802 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003803 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003804 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003805 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003806 }
3807
Johan Hedberg33e38b32013-03-15 17:07:05 -05003808unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003809 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003810
Antti Julkuf6422ec2011-06-22 13:11:56 +03003811 return err;
3812}
3813
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003814static void set_bredr_scan(struct hci_request *req)
3815{
3816 struct hci_dev *hdev = req->hdev;
3817 u8 scan = 0;
3818
3819 /* Ensure that fast connectable is disabled. This function will
3820 * not do anything if the page scan parameters are already what
3821 * they should be.
3822 */
3823 write_fast_connectable(req, false);
3824
3825 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3826 scan |= SCAN_PAGE;
3827 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3828 scan |= SCAN_INQUIRY;
3829
3830 if (scan)
3831 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3832}
3833
Johan Hedberg0663ca22013-10-02 13:43:14 +03003834static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3835{
3836 struct pending_cmd *cmd;
3837
3838 BT_DBG("status 0x%02x", status);
3839
3840 hci_dev_lock(hdev);
3841
3842 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3843 if (!cmd)
3844 goto unlock;
3845
3846 if (status) {
3847 u8 mgmt_err = mgmt_status(status);
3848
3849 /* We need to restore the flag if related HCI commands
3850 * failed.
3851 */
3852 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3853
3854 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3855 } else {
3856 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3857 new_settings(hdev, cmd->sk);
3858 }
3859
3860 mgmt_pending_remove(cmd);
3861
3862unlock:
3863 hci_dev_unlock(hdev);
3864}
3865
3866static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3867{
3868 struct mgmt_mode *cp = data;
3869 struct pending_cmd *cmd;
3870 struct hci_request req;
3871 int err;
3872
3873 BT_DBG("request for %s", hdev->name);
3874
3875 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3876 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3877 MGMT_STATUS_NOT_SUPPORTED);
3878
3879 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3880 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3881 MGMT_STATUS_REJECTED);
3882
3883 if (cp->val != 0x00 && cp->val != 0x01)
3884 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3885 MGMT_STATUS_INVALID_PARAMS);
3886
3887 hci_dev_lock(hdev);
3888
3889 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3890 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3891 goto unlock;
3892 }
3893
3894 if (!hdev_is_powered(hdev)) {
3895 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003896 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3897 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3898 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3899 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3900 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3901 }
3902
3903 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3904
3905 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3906 if (err < 0)
3907 goto unlock;
3908
3909 err = new_settings(hdev, sk);
3910 goto unlock;
3911 }
3912
3913 /* Reject disabling when powered on */
3914 if (!cp->val) {
3915 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3916 MGMT_STATUS_REJECTED);
3917 goto unlock;
3918 }
3919
3920 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3921 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3922 MGMT_STATUS_BUSY);
3923 goto unlock;
3924 }
3925
3926 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3927 if (!cmd) {
3928 err = -ENOMEM;
3929 goto unlock;
3930 }
3931
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07003932 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03003933 * generates the correct flags.
3934 */
3935 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3936
3937 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003938
3939 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3940 set_bredr_scan(&req);
3941
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07003942 /* Since only the advertising data flags will change, there
3943 * is no need to update the scan response data.
3944 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07003945 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003946
Johan Hedberg0663ca22013-10-02 13:43:14 +03003947 err = hci_req_run(&req, set_bredr_complete);
3948 if (err < 0)
3949 mgmt_pending_remove(cmd);
3950
3951unlock:
3952 hci_dev_unlock(hdev);
3953 return err;
3954}
3955
Johan Hedberg3f706b72013-01-20 14:27:16 +02003956static bool ltk_is_valid(struct mgmt_ltk_info *key)
3957{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003958 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3959 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003960 if (key->master != 0x00 && key->master != 0x01)
3961 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003962 if (!bdaddr_type_is_le(key->addr.type))
3963 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003964 return true;
3965}
3966
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003967static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003968 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003969{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003970 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3971 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003972 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003973
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003974 BT_DBG("request for %s", hdev->name);
3975
3976 if (!lmp_le_capable(hdev))
3977 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3978 MGMT_STATUS_NOT_SUPPORTED);
3979
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003980 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003981
3982 expected_len = sizeof(*cp) + key_count *
3983 sizeof(struct mgmt_ltk_info);
3984 if (expected_len != len) {
3985 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003986 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003987 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003988 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003989 }
3990
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003991 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003992
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003993 for (i = 0; i < key_count; i++) {
3994 struct mgmt_ltk_info *key = &cp->keys[i];
3995
Johan Hedberg3f706b72013-01-20 14:27:16 +02003996 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003997 return cmd_status(sk, hdev->id,
3998 MGMT_OP_LOAD_LONG_TERM_KEYS,
3999 MGMT_STATUS_INVALID_PARAMS);
4000 }
4001
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004002 hci_dev_lock(hdev);
4003
4004 hci_smp_ltks_clear(hdev);
4005
4006 for (i = 0; i < key_count; i++) {
4007 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004008 u8 type, addr_type;
4009
4010 if (key->addr.type == BDADDR_LE_PUBLIC)
4011 addr_type = ADDR_LE_DEV_PUBLIC;
4012 else
4013 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004014
4015 if (key->master)
4016 type = HCI_SMP_LTK;
4017 else
4018 type = HCI_SMP_LTK_SLAVE;
4019
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004020 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004021 type, 0, key->authenticated, key->val,
4022 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004023 }
4024
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004025 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4026 NULL, 0);
4027
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004028 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004029
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004030 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004031}
4032
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004033static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004034 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4035 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004036 bool var_len;
4037 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004038} mgmt_handlers[] = {
4039 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004040 { read_version, false, MGMT_READ_VERSION_SIZE },
4041 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4042 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4043 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4044 { set_powered, false, MGMT_SETTING_SIZE },
4045 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4046 { set_connectable, false, MGMT_SETTING_SIZE },
4047 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4048 { set_pairable, false, MGMT_SETTING_SIZE },
4049 { set_link_security, false, MGMT_SETTING_SIZE },
4050 { set_ssp, false, MGMT_SETTING_SIZE },
4051 { set_hs, false, MGMT_SETTING_SIZE },
4052 { set_le, false, MGMT_SETTING_SIZE },
4053 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4054 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4055 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4056 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4057 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4058 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4059 { disconnect, false, MGMT_DISCONNECT_SIZE },
4060 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4061 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4062 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4063 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4064 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4065 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4066 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4067 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4068 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4069 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4070 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4071 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
4072 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
4073 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4074 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4075 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4076 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4077 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4078 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004079 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004080 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004081 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004082 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004083 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004084};
4085
4086
Johan Hedberg03811012010-12-08 00:21:06 +02004087int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4088{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004089 void *buf;
4090 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004091 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004092 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004093 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004094 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004095 int err;
4096
4097 BT_DBG("got %zu bytes", msglen);
4098
4099 if (msglen < sizeof(*hdr))
4100 return -EINVAL;
4101
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004102 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004103 if (!buf)
4104 return -ENOMEM;
4105
4106 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4107 err = -EFAULT;
4108 goto done;
4109 }
4110
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004111 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004112 opcode = __le16_to_cpu(hdr->opcode);
4113 index = __le16_to_cpu(hdr->index);
4114 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004115
4116 if (len != msglen - sizeof(*hdr)) {
4117 err = -EINVAL;
4118 goto done;
4119 }
4120
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004121 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004122 hdev = hci_dev_get(index);
4123 if (!hdev) {
4124 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004125 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004126 goto done;
4127 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004128
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004129 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4130 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004131 err = cmd_status(sk, index, opcode,
4132 MGMT_STATUS_INVALID_INDEX);
4133 goto done;
4134 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004135 }
4136
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004137 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004138 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004139 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004140 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004141 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004142 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004143 }
4144
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004145 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004146 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004147 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004148 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004149 goto done;
4150 }
4151
Johan Hedbergbe22b542012-03-01 22:24:41 +02004152 handler = &mgmt_handlers[opcode];
4153
4154 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004155 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004156 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004157 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004158 goto done;
4159 }
4160
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004161 if (hdev)
4162 mgmt_init_hdev(sk, hdev);
4163
4164 cp = buf + sizeof(*hdr);
4165
Johan Hedbergbe22b542012-03-01 22:24:41 +02004166 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004167 if (err < 0)
4168 goto done;
4169
Johan Hedberg03811012010-12-08 00:21:06 +02004170 err = msglen;
4171
4172done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004173 if (hdev)
4174 hci_dev_put(hdev);
4175
Johan Hedberg03811012010-12-08 00:21:06 +02004176 kfree(buf);
4177 return err;
4178}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004179
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004180void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004181{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004182 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004183 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004184
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004185 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004186}
4187
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004188void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004189{
Johan Hedberg5f159032012-03-02 03:13:19 +02004190 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004191
Marcel Holtmann1514b892013-10-06 08:25:01 -07004192 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004193 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004194
Johan Hedberg744cf192011-11-08 20:40:14 +02004195 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004196
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004197 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004198}
4199
Johan Hedberg229ab392013-03-15 17:06:53 -05004200static void powered_complete(struct hci_dev *hdev, u8 status)
4201{
4202 struct cmd_lookup match = { NULL, hdev };
4203
4204 BT_DBG("status 0x%02x", status);
4205
4206 hci_dev_lock(hdev);
4207
4208 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4209
4210 new_settings(hdev, match.sk);
4211
4212 hci_dev_unlock(hdev);
4213
4214 if (match.sk)
4215 sock_put(match.sk);
4216}
4217
Johan Hedberg70da6242013-03-15 17:06:51 -05004218static int powered_update_hci(struct hci_dev *hdev)
4219{
Johan Hedberg890ea892013-03-15 17:06:52 -05004220 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004221 u8 link_sec;
4222
Johan Hedberg890ea892013-03-15 17:06:52 -05004223 hci_req_init(&req, hdev);
4224
Johan Hedberg70da6242013-03-15 17:06:51 -05004225 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4226 !lmp_host_ssp_capable(hdev)) {
4227 u8 ssp = 1;
4228
Johan Hedberg890ea892013-03-15 17:06:52 -05004229 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004230 }
4231
Johan Hedbergc73eee92013-04-19 18:35:21 +03004232 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4233 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004234 struct hci_cp_write_le_host_supported cp;
4235
4236 cp.le = 1;
4237 cp.simul = lmp_le_br_capable(hdev);
4238
4239 /* Check first if we already have the right
4240 * host state (host features set)
4241 */
4242 if (cp.le != lmp_host_le_capable(hdev) ||
4243 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004244 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4245 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004246 }
4247
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004248 if (lmp_le_capable(hdev)) {
4249 /* Set random address to static address if configured */
4250 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4251 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4252 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004253
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004254 /* Make sure the controller has a good default for
4255 * advertising data. This also applies to the case
4256 * where BR/EDR was toggled during the AUTO_OFF phase.
4257 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004258 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004259 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004260 update_scan_rsp_data(&req);
4261 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004262
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004263 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4264 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004265 }
4266
Johan Hedberg70da6242013-03-15 17:06:51 -05004267 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4268 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004269 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4270 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004271
4272 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004273 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4274 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004275 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004276 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004277 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004278 }
4279
Johan Hedberg229ab392013-03-15 17:06:53 -05004280 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004281}
4282
Johan Hedberg744cf192011-11-08 20:40:14 +02004283int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004284{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004285 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004286 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4287 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004288 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004289
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004290 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4291 return 0;
4292
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004293 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004294 if (powered_update_hci(hdev) == 0)
4295 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004296
Johan Hedberg229ab392013-03-15 17:06:53 -05004297 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4298 &match);
4299 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004300 }
4301
Johan Hedberg229ab392013-03-15 17:06:53 -05004302 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4303 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4304
4305 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4306 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4307 zero_cod, sizeof(zero_cod), NULL);
4308
4309new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004310 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004311
4312 if (match.sk)
4313 sock_put(match.sk);
4314
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004315 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004316}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004317
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004318void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004319{
4320 struct pending_cmd *cmd;
4321 u8 status;
4322
4323 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4324 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004325 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004326
4327 if (err == -ERFKILL)
4328 status = MGMT_STATUS_RFKILLED;
4329 else
4330 status = MGMT_STATUS_FAILED;
4331
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004332 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004333
4334 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004335}
4336
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004337void mgmt_discoverable_timeout(struct hci_dev *hdev)
4338{
4339 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004340
4341 hci_dev_lock(hdev);
4342
4343 /* When discoverable timeout triggers, then just make sure
4344 * the limited discoverable flag is cleared. Even in the case
4345 * of a timeout triggered from general discoverable, it is
4346 * safe to unconditionally clear the flag.
4347 */
4348 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
4349
4350 hci_req_init(&req, hdev);
Johan Hedberg4b580612013-10-19 23:38:21 +03004351 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4352 u8 scan = SCAN_PAGE;
4353 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
4354 sizeof(scan), &scan);
4355 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004356 update_class(&req);
4357 hci_req_run(&req, NULL);
4358
4359 hdev->discov_timeout = 0;
4360
4361 hci_dev_unlock(hdev);
4362}
4363
Marcel Holtmann86a75642013-10-15 06:33:54 -07004364void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004365{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004366 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004367
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004368 /* Nothing needed here if there's a pending command since that
4369 * commands request completion callback takes care of everything
4370 * necessary.
4371 */
4372 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004373 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004374
Marcel Holtmann86a75642013-10-15 06:33:54 -07004375 if (discoverable)
4376 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4377 else
4378 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004379
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004380 if (changed)
Marcel Holtmann86a75642013-10-15 06:33:54 -07004381 new_settings(hdev, NULL);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004382}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004383
Marcel Holtmanna3309162013-10-15 06:33:55 -07004384void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004385{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004386 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004387
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004388 /* Nothing needed here if there's a pending command since that
4389 * commands request completion callback takes care of everything
4390 * necessary.
4391 */
4392 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004393 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004394
Marcel Holtmanna3309162013-10-15 06:33:55 -07004395 if (connectable)
4396 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4397 else
4398 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004399
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004400 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004401 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004402}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004403
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004404void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004405{
Johan Hedbergca69b792011-11-11 18:10:00 +02004406 u8 mgmt_err = mgmt_status(status);
4407
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004408 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004409 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004410 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004411
4412 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004413 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004414 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004415}
4416
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004417void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4418 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004419{
Johan Hedberg86742e12011-11-07 23:13:38 +02004420 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004421
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004422 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004423
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004424 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004425 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004426 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004427 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004428 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004429 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004430
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004431 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004432}
Johan Hedbergf7520542011-01-20 12:34:39 +02004433
Marcel Holtmann083368f2013-10-15 14:26:29 -07004434void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004435{
4436 struct mgmt_ev_new_long_term_key ev;
4437
4438 memset(&ev, 0, sizeof(ev));
4439
4440 ev.store_hint = persistent;
4441 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004442 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004443 ev.key.authenticated = key->authenticated;
4444 ev.key.enc_size = key->enc_size;
4445 ev.key.ediv = key->ediv;
4446
4447 if (key->type == HCI_SMP_LTK)
4448 ev.key.master = 1;
4449
4450 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4451 memcpy(ev.key.val, key->val, sizeof(key->val));
4452
Marcel Holtmann083368f2013-10-15 14:26:29 -07004453 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004454}
4455
Marcel Holtmann94933992013-10-15 10:26:39 -07004456static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4457 u8 data_len)
4458{
4459 eir[eir_len++] = sizeof(type) + data_len;
4460 eir[eir_len++] = type;
4461 memcpy(&eir[eir_len], data, data_len);
4462 eir_len += data_len;
4463
4464 return eir_len;
4465}
4466
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004467void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4468 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4469 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004470{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004471 char buf[512];
4472 struct mgmt_ev_device_connected *ev = (void *) buf;
4473 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004474
Johan Hedbergb644ba32012-01-17 21:48:47 +02004475 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004476 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004477
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004478 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004479
Johan Hedbergb644ba32012-01-17 21:48:47 +02004480 if (name_len > 0)
4481 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004482 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004483
4484 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004485 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004486 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004487
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004488 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004489
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004490 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4491 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004492}
4493
Johan Hedberg8962ee72011-01-20 12:40:27 +02004494static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4495{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004496 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004497 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004498 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004499
Johan Hedberg88c3df12012-02-09 14:27:38 +02004500 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4501 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004502
Johan Hedbergaee9b212012-02-18 15:07:59 +02004503 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004504 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004505
4506 *sk = cmd->sk;
4507 sock_hold(*sk);
4508
Johan Hedberga664b5b2011-02-19 12:06:02 -03004509 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004510}
4511
Johan Hedberg124f6e32012-02-09 13:50:12 +02004512static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004513{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004514 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004515 struct mgmt_cp_unpair_device *cp = cmd->param;
4516 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004517
4518 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004519 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4520 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004521
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004522 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4523
Johan Hedbergaee9b212012-02-18 15:07:59 +02004524 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004525
4526 mgmt_pending_remove(cmd);
4527}
4528
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004529void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4530 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004531{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004532 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004533 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004534
Johan Hedberg744cf192011-11-08 20:40:14 +02004535 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004536
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004537 bacpy(&ev.addr.bdaddr, bdaddr);
4538 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4539 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004540
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004541 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004542
4543 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004544 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004545
Johan Hedberg124f6e32012-02-09 13:50:12 +02004546 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004547 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004548}
4549
Marcel Holtmann78929242013-10-06 23:55:47 -07004550void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4551 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004552{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004553 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004554 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004555
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004556 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4557 hdev);
4558
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004559 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004560 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004561 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004562
Johan Hedberg88c3df12012-02-09 14:27:38 +02004563 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004564 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004565
Marcel Holtmann78929242013-10-06 23:55:47 -07004566 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4567 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004568
Johan Hedberga664b5b2011-02-19 12:06:02 -03004569 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004570}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004571
Marcel Holtmann445608d2013-10-06 23:55:48 -07004572void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4573 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004574{
4575 struct mgmt_ev_connect_failed ev;
4576
Johan Hedberg4c659c32011-11-07 23:13:39 +02004577 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004578 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004579 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004580
Marcel Holtmann445608d2013-10-06 23:55:48 -07004581 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004582}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004583
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004584void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004585{
4586 struct mgmt_ev_pin_code_request ev;
4587
Johan Hedbergd8457692012-02-17 14:24:57 +02004588 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004589 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004590 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004591
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004592 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004593}
4594
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004595void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4596 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004597{
4598 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004599 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004600
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004601 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004602 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004603 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004604
Johan Hedbergd8457692012-02-17 14:24:57 +02004605 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004606 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004607
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004608 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
4609 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004610
Johan Hedberga664b5b2011-02-19 12:06:02 -03004611 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004612}
4613
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004614void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4615 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004616{
4617 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004618 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004619
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004620 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004621 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004622 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004623
Johan Hedbergd8457692012-02-17 14:24:57 +02004624 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004625 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004626
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004627 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
4628 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004629
Johan Hedberga664b5b2011-02-19 12:06:02 -03004630 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004631}
Johan Hedberga5c29682011-02-19 12:05:57 -03004632
Johan Hedberg744cf192011-11-08 20:40:14 +02004633int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004634 u8 link_type, u8 addr_type, __le32 value,
4635 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004636{
4637 struct mgmt_ev_user_confirm_request ev;
4638
Johan Hedberg744cf192011-11-08 20:40:14 +02004639 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004640
Johan Hedberg272d90d2012-02-09 15:26:12 +02004641 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004642 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004643 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004644 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004645
Johan Hedberg744cf192011-11-08 20:40:14 +02004646 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004647 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004648}
4649
Johan Hedberg272d90d2012-02-09 15:26:12 +02004650int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004651 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004652{
4653 struct mgmt_ev_user_passkey_request ev;
4654
4655 BT_DBG("%s", hdev->name);
4656
Johan Hedberg272d90d2012-02-09 15:26:12 +02004657 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004658 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004659
4660 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004661 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004662}
4663
Brian Gix0df4c182011-11-16 13:53:13 -08004664static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004665 u8 link_type, u8 addr_type, u8 status,
4666 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004667{
4668 struct pending_cmd *cmd;
4669 struct mgmt_rp_user_confirm_reply rp;
4670 int err;
4671
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004672 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004673 if (!cmd)
4674 return -ENOENT;
4675
Johan Hedberg272d90d2012-02-09 15:26:12 +02004676 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004677 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004678 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004679 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004680
Johan Hedberga664b5b2011-02-19 12:06:02 -03004681 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004682
4683 return err;
4684}
4685
Johan Hedberg744cf192011-11-08 20:40:14 +02004686int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004687 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004688{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004689 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004690 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004691}
4692
Johan Hedberg272d90d2012-02-09 15:26:12 +02004693int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004694 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004695{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004696 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004697 status,
4698 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004699}
Johan Hedberg2a611692011-02-19 12:06:00 -03004700
Brian Gix604086b2011-11-23 08:28:33 -08004701int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004702 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004703{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004704 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004705 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004706}
4707
Johan Hedberg272d90d2012-02-09 15:26:12 +02004708int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004709 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004710{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004711 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004712 status,
4713 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004714}
4715
Johan Hedberg92a25252012-09-06 18:39:26 +03004716int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4717 u8 link_type, u8 addr_type, u32 passkey,
4718 u8 entered)
4719{
4720 struct mgmt_ev_passkey_notify ev;
4721
4722 BT_DBG("%s", hdev->name);
4723
4724 bacpy(&ev.addr.bdaddr, bdaddr);
4725 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4726 ev.passkey = __cpu_to_le32(passkey);
4727 ev.entered = entered;
4728
4729 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4730}
4731
Marcel Holtmanne5460992013-10-15 14:26:23 -07004732void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4733 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004734{
4735 struct mgmt_ev_auth_failed ev;
4736
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004737 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004738 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004739 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004740
Marcel Holtmanne5460992013-10-15 14:26:23 -07004741 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004742}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004743
Marcel Holtmann464996a2013-10-15 14:26:24 -07004744void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004745{
4746 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07004747 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004748
4749 if (status) {
4750 u8 mgmt_err = mgmt_status(status);
4751 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004752 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07004753 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004754 }
4755
Marcel Holtmann464996a2013-10-15 14:26:24 -07004756 if (test_bit(HCI_AUTH, &hdev->flags))
4757 changed = !test_and_set_bit(HCI_LINK_SECURITY,
4758 &hdev->dev_flags);
4759 else
4760 changed = test_and_clear_bit(HCI_LINK_SECURITY,
4761 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02004762
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004763 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004764 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004765
Johan Hedberg47990ea2012-02-22 11:58:37 +02004766 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07004767 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004768
4769 if (match.sk)
4770 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004771}
4772
Johan Hedberg890ea892013-03-15 17:06:52 -05004773static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004774{
Johan Hedberg890ea892013-03-15 17:06:52 -05004775 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004776 struct hci_cp_write_eir cp;
4777
Johan Hedberg976eb202012-10-24 21:12:01 +03004778 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004779 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004780
Johan Hedbergc80da272012-02-22 15:38:48 +02004781 memset(hdev->eir, 0, sizeof(hdev->eir));
4782
Johan Hedbergcacaf522012-02-21 00:52:42 +02004783 memset(&cp, 0, sizeof(cp));
4784
Johan Hedberg890ea892013-03-15 17:06:52 -05004785 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004786}
4787
Marcel Holtmann3e248562013-10-15 14:26:25 -07004788void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004789{
4790 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004791 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004792 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004793
4794 if (status) {
4795 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004796
4797 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004798 &hdev->dev_flags)) {
4799 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004800 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004801 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004802
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004803 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4804 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004805 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004806 }
4807
4808 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004809 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004810 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004811 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4812 if (!changed)
4813 changed = test_and_clear_bit(HCI_HS_ENABLED,
4814 &hdev->dev_flags);
4815 else
4816 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004817 }
4818
4819 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4820
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004821 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07004822 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004823
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004824 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004825 sock_put(match.sk);
4826
Johan Hedberg890ea892013-03-15 17:06:52 -05004827 hci_req_init(&req, hdev);
4828
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004829 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004830 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004831 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004832 clear_eir(&req);
4833
4834 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004835}
4836
Johan Hedberg92da6092013-03-15 17:06:55 -05004837static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004838{
4839 struct cmd_lookup *match = data;
4840
Johan Hedberg90e70452012-02-23 23:09:40 +02004841 if (match->sk == NULL) {
4842 match->sk = cmd->sk;
4843 sock_hold(match->sk);
4844 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004845}
4846
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07004847void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
4848 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004849{
Johan Hedberg90e70452012-02-23 23:09:40 +02004850 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004851
Johan Hedberg92da6092013-03-15 17:06:55 -05004852 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4853 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4854 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004855
4856 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07004857 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
4858 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004859
4860 if (match.sk)
4861 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004862}
4863
Marcel Holtmann7667da32013-10-15 14:26:27 -07004864void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004865{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004866 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004867 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004868
Johan Hedberg13928972013-03-15 17:07:00 -05004869 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07004870 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004871
4872 memset(&ev, 0, sizeof(ev));
4873 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004874 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004875
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004876 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004877 if (!cmd) {
4878 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004879
Johan Hedberg13928972013-03-15 17:07:00 -05004880 /* If this is a HCI command related to powering on the
4881 * HCI dev don't send any mgmt signals.
4882 */
4883 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07004884 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004885 }
4886
Marcel Holtmann7667da32013-10-15 14:26:27 -07004887 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4888 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004889}
Szymon Jancc35938b2011-03-22 13:12:21 +01004890
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004891void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
4892 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004893{
4894 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01004895
Johan Hedberg744cf192011-11-08 20:40:14 +02004896 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004897
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004898 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004899 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004900 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01004901
4902 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004903 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4904 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004905 } else {
4906 struct mgmt_rp_read_local_oob_data rp;
4907
4908 memcpy(rp.hash, hash, sizeof(rp.hash));
4909 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4910
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004911 cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4912 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004913 }
4914
4915 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01004916}
Johan Hedberge17acd42011-03-30 23:57:16 +03004917
Marcel Holtmann901801b2013-10-06 23:55:51 -07004918void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4919 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4920 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004921{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004922 char buf[512];
4923 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004924 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004925
Andre Guedes12602d02013-04-30 15:29:40 -03004926 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004927 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004928
Johan Hedberg1dc06092012-01-15 21:01:23 +02004929 /* Leave 5 bytes for a potential CoD field */
4930 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004931 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004932
Johan Hedberg1dc06092012-01-15 21:01:23 +02004933 memset(buf, 0, sizeof(buf));
4934
Johan Hedberge319d2e2012-01-15 19:51:59 +02004935 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004936 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004937 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004938 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304939 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004940 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304941 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004942
Johan Hedberg1dc06092012-01-15 21:01:23 +02004943 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004944 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004945
Johan Hedberg1dc06092012-01-15 21:01:23 +02004946 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4947 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004948 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004949
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004950 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004951 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004952
Marcel Holtmann901801b2013-10-06 23:55:51 -07004953 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004954}
Johan Hedberga88a9652011-03-30 13:18:12 +03004955
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004956void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4957 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004958{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004959 struct mgmt_ev_device_found *ev;
4960 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4961 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004962
Johan Hedbergb644ba32012-01-17 21:48:47 +02004963 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004964
Johan Hedbergb644ba32012-01-17 21:48:47 +02004965 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004966
Johan Hedbergb644ba32012-01-17 21:48:47 +02004967 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004968 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004969 ev->rssi = rssi;
4970
4971 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004972 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004973
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004974 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004975
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004976 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004977}
Johan Hedberg314b2382011-04-27 10:29:57 -04004978
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004979void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004980{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004981 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004982 struct pending_cmd *cmd;
4983
Andre Guedes343fb142011-11-22 17:14:19 -03004984 BT_DBG("%s discovering %u", hdev->name, discovering);
4985
Johan Hedberg164a6e72011-11-01 17:06:44 +02004986 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004987 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004988 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004989 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004990
4991 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004992 u8 type = hdev->discovery.type;
4993
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004994 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4995 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004996 mgmt_pending_remove(cmd);
4997 }
4998
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004999 memset(&ev, 0, sizeof(ev));
5000 ev.type = hdev->discovery.type;
5001 ev.discovering = discovering;
5002
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005003 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04005004}
Antti Julku5e762442011-08-25 16:48:02 +03005005
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005006int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005007{
5008 struct pending_cmd *cmd;
5009 struct mgmt_ev_device_blocked ev;
5010
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005011 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005012
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005013 bacpy(&ev.addr.bdaddr, bdaddr);
5014 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005015
Johan Hedberg744cf192011-11-08 20:40:14 +02005016 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005017 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005018}
5019
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005020int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005021{
5022 struct pending_cmd *cmd;
5023 struct mgmt_ev_device_unblocked ev;
5024
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005025 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005026
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005027 bacpy(&ev.addr.bdaddr, bdaddr);
5028 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005029
Johan Hedberg744cf192011-11-08 20:40:14 +02005030 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005031 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005032}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005033
5034static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5035{
5036 BT_DBG("%s status %u", hdev->name, status);
5037
5038 /* Clear the advertising mgmt setting if we failed to re-enable it */
5039 if (status) {
5040 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005041 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005042 }
5043}
5044
5045void mgmt_reenable_advertising(struct hci_dev *hdev)
5046{
5047 struct hci_request req;
5048
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005049 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005050 return;
5051
5052 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5053 return;
5054
5055 hci_req_init(&req, hdev);
5056 enable_advertising(&req);
5057
5058 /* If this fails we have no option but to let user space know
5059 * that we've disabled advertising.
5060 */
5061 if (hci_req_run(&req, adv_enable_complete) < 0) {
5062 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005063 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005064 }
5065}