blob: f39bab059fcc20bd9338614ba6f5091e2e6ccab1 [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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200203
Andre Guedes790eff42012-06-07 19:05:46 -0300204 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200220 kfree_skb(skb);
221
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300222 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223}
224
Johan Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700539static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
540{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700541 u8 ad_len = 0;
542 size_t name_len;
543
544 name_len = strlen(hdev->dev_name);
545 if (name_len > 0) {
546 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
547
548 if (name_len > max_len) {
549 name_len = max_len;
550 ptr[1] = EIR_NAME_SHORT;
551 } else
552 ptr[1] = EIR_NAME_COMPLETE;
553
554 ptr[0] = name_len + 1;
555
556 memcpy(ptr + 2, hdev->dev_name, name_len);
557
558 ad_len += (name_len + 2);
559 ptr += (name_len + 2);
560 }
561
562 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700563}
564
565static void update_scan_rsp_data(struct hci_request *req)
566{
567 struct hci_dev *hdev = req->hdev;
568 struct hci_cp_le_set_scan_rsp_data cp;
569 u8 len;
570
Johan Hedberg7751ef12013-10-19 23:38:15 +0300571 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700572 return;
573
574 memset(&cp, 0, sizeof(cp));
575
576 len = create_scan_rsp_data(hdev, cp.data);
577
Johan Hedbergeb438b52013-10-16 15:31:07 +0300578 if (hdev->scan_rsp_data_len == len &&
579 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700580 return;
581
Johan Hedbergeb438b52013-10-16 15:31:07 +0300582 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
583 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700584
585 cp.length = len;
586
587 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
588}
589
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700590static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700591{
592 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700593
594 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
595 flags |= LE_AD_GENERAL;
596
597 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
598 if (lmp_le_br_capable(hdev))
599 flags |= LE_AD_SIM_LE_BREDR_CTRL;
600 if (lmp_host_le_br_capable(hdev))
601 flags |= LE_AD_SIM_LE_BREDR_HOST;
602 } else {
603 flags |= LE_AD_NO_BREDR;
604 }
605
606 if (flags) {
607 BT_DBG("adv flags 0x%02x", flags);
608
609 ptr[0] = 2;
610 ptr[1] = EIR_FLAGS;
611 ptr[2] = flags;
612
613 ad_len += 3;
614 ptr += 3;
615 }
616
617 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
618 ptr[0] = 2;
619 ptr[1] = EIR_TX_POWER;
620 ptr[2] = (u8) hdev->adv_tx_power;
621
622 ad_len += 3;
623 ptr += 3;
624 }
625
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700626 return ad_len;
627}
628
Marcel Holtmann5947f4b2013-10-16 00:16:50 -0700629static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700630{
631 struct hci_dev *hdev = req->hdev;
632 struct hci_cp_le_set_adv_data cp;
633 u8 len;
634
635 if (!lmp_le_capable(hdev))
636 return;
637
638 memset(&cp, 0, sizeof(cp));
639
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700640 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700641
642 if (hdev->adv_data_len == len &&
643 memcmp(cp.data, hdev->adv_data, len) == 0)
644 return;
645
646 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
647 hdev->adv_data_len = len;
648
649 cp.length = len;
650
651 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
652}
653
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300654static void create_eir(struct hci_dev *hdev, u8 *data)
655{
656 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300657 size_t name_len;
658
659 name_len = strlen(hdev->dev_name);
660
661 if (name_len > 0) {
662 /* EIR Data type */
663 if (name_len > 48) {
664 name_len = 48;
665 ptr[1] = EIR_NAME_SHORT;
666 } else
667 ptr[1] = EIR_NAME_COMPLETE;
668
669 /* EIR Data length */
670 ptr[0] = name_len + 1;
671
672 memcpy(ptr + 2, hdev->dev_name, name_len);
673
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300674 ptr += (name_len + 2);
675 }
676
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100677 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700678 ptr[0] = 2;
679 ptr[1] = EIR_TX_POWER;
680 ptr[2] = (u8) hdev->inq_tx_power;
681
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700682 ptr += 3;
683 }
684
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700685 if (hdev->devid_source > 0) {
686 ptr[0] = 9;
687 ptr[1] = EIR_DEVICE_ID;
688
689 put_unaligned_le16(hdev->devid_source, ptr + 2);
690 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
691 put_unaligned_le16(hdev->devid_product, ptr + 6);
692 put_unaligned_le16(hdev->devid_version, ptr + 8);
693
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700694 ptr += 10;
695 }
696
Johan Hedberg213202e2013-01-27 00:31:33 +0200697 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200698 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200699 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300700}
701
Johan Hedberg890ea892013-03-15 17:06:52 -0500702static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300703{
Johan Hedberg890ea892013-03-15 17:06:52 -0500704 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300705 struct hci_cp_write_eir cp;
706
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200707 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500708 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200709
Johan Hedberg976eb202012-10-24 21:12:01 +0300710 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500711 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300712
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200713 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500714 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300715
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200716 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500717 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300718
719 memset(&cp, 0, sizeof(cp));
720
721 create_eir(hdev, cp.data);
722
723 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500724 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300725
726 memcpy(hdev->eir, cp.data, sizeof(cp.data));
727
Johan Hedberg890ea892013-03-15 17:06:52 -0500728 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300729}
730
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200731static u8 get_service_classes(struct hci_dev *hdev)
732{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300733 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200734 u8 val = 0;
735
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300736 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200737 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200738
739 return val;
740}
741
Johan Hedberg890ea892013-03-15 17:06:52 -0500742static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200743{
Johan Hedberg890ea892013-03-15 17:06:52 -0500744 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200745 u8 cod[3];
746
747 BT_DBG("%s", hdev->name);
748
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200749 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500750 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200751
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200752 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500753 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200754
755 cod[0] = hdev->minor_class;
756 cod[1] = hdev->major_class;
757 cod[2] = get_service_classes(hdev);
758
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700759 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
760 cod[1] |= 0x20;
761
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200762 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500763 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200764
Johan Hedberg890ea892013-03-15 17:06:52 -0500765 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200766}
767
Johan Hedberg7d785252011-12-15 00:47:39 +0200768static void service_cache_off(struct work_struct *work)
769{
770 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300771 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500772 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200773
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200774 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200775 return;
776
Johan Hedberg890ea892013-03-15 17:06:52 -0500777 hci_req_init(&req, hdev);
778
Johan Hedberg7d785252011-12-15 00:47:39 +0200779 hci_dev_lock(hdev);
780
Johan Hedberg890ea892013-03-15 17:06:52 -0500781 update_eir(&req);
782 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200783
784 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500785
786 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200787}
788
Johan Hedberg6a919082012-02-28 06:17:26 +0200789static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200790{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200791 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200792 return;
793
Johan Hedberg4f87da82012-03-02 19:55:56 +0200794 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200795
Johan Hedberg4f87da82012-03-02 19:55:56 +0200796 /* Non-mgmt controlled devices get this bit set
797 * implicitly so that pairing works for them, however
798 * for mgmt we require user-space to explicitly enable
799 * it
800 */
801 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200802}
803
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200804static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300805 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200806{
807 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200808
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200809 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200810
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300811 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200812
Johan Hedberg03811012010-12-08 00:21:06 +0200813 memset(&rp, 0, sizeof(rp));
814
Johan Hedberg03811012010-12-08 00:21:06 +0200815 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200816
817 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200818 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200819
820 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
821 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
822
823 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200824
825 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200826 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200827
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300828 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200829
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200830 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300831 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200832}
833
834static void mgmt_pending_free(struct pending_cmd *cmd)
835{
836 sock_put(cmd->sk);
837 kfree(cmd->param);
838 kfree(cmd);
839}
840
841static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300842 struct hci_dev *hdev, void *data,
843 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200844{
845 struct pending_cmd *cmd;
846
Andre Guedes12b94562012-06-07 19:05:45 -0300847 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200848 if (!cmd)
849 return NULL;
850
851 cmd->opcode = opcode;
852 cmd->index = hdev->id;
853
Andre Guedes12b94562012-06-07 19:05:45 -0300854 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200855 if (!cmd->param) {
856 kfree(cmd);
857 return NULL;
858 }
859
860 if (data)
861 memcpy(cmd->param, data, len);
862
863 cmd->sk = sk;
864 sock_hold(sk);
865
866 list_add(&cmd->list, &hdev->mgmt_pending);
867
868 return cmd;
869}
870
871static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300872 void (*cb)(struct pending_cmd *cmd,
873 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300874 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200875{
Andre Guedesa3d09352013-02-01 11:21:30 -0300876 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200877
Andre Guedesa3d09352013-02-01 11:21:30 -0300878 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200879 if (opcode > 0 && cmd->opcode != opcode)
880 continue;
881
882 cb(cmd, data);
883 }
884}
885
886static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
887{
888 struct pending_cmd *cmd;
889
890 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
891 if (cmd->opcode == opcode)
892 return cmd;
893 }
894
895 return NULL;
896}
897
898static void mgmt_pending_remove(struct pending_cmd *cmd)
899{
900 list_del(&cmd->list);
901 mgmt_pending_free(cmd);
902}
903
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200904static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200905{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200906 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200907
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200908 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300909 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200910}
911
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200912static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300913 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200914{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300915 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200916 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200917 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200918
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200919 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200920
Johan Hedberga7e80f22013-01-09 16:05:19 +0200921 if (cp->val != 0x00 && cp->val != 0x01)
922 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
923 MGMT_STATUS_INVALID_PARAMS);
924
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300925 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200926
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300927 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
928 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
929 MGMT_STATUS_BUSY);
930 goto failed;
931 }
932
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100933 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
934 cancel_delayed_work(&hdev->power_off);
935
936 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200937 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
938 data, len);
939 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100940 goto failed;
941 }
942 }
943
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200944 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200945 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200946 goto failed;
947 }
948
Johan Hedberg03811012010-12-08 00:21:06 +0200949 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
950 if (!cmd) {
951 err = -ENOMEM;
952 goto failed;
953 }
954
955 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200956 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200957 else
Johan Hedberg19202572013-01-14 22:33:51 +0200958 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200959
960 err = 0;
961
962failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300963 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200964 return err;
965}
966
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300967static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
968 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200969{
970 struct sk_buff *skb;
971 struct mgmt_hdr *hdr;
972
Andre Guedes790eff42012-06-07 19:05:46 -0300973 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200974 if (!skb)
975 return -ENOMEM;
976
977 hdr = (void *) skb_put(skb, sizeof(*hdr));
978 hdr->opcode = cpu_to_le16(event);
979 if (hdev)
980 hdr->index = cpu_to_le16(hdev->id);
981 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530982 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200983 hdr->len = cpu_to_le16(data_len);
984
985 if (data)
986 memcpy(skb_put(skb, data_len), data, data_len);
987
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100988 /* Time stamp */
989 __net_timestamp(skb);
990
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200991 hci_send_to_control(skb, skip_sk);
992 kfree_skb(skb);
993
994 return 0;
995}
996
997static int new_settings(struct hci_dev *hdev, struct sock *skip)
998{
999 __le32 ev;
1000
1001 ev = cpu_to_le32(get_current_settings(hdev));
1002
1003 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1004}
1005
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001006struct cmd_lookup {
1007 struct sock *sk;
1008 struct hci_dev *hdev;
1009 u8 mgmt_status;
1010};
1011
1012static void settings_rsp(struct pending_cmd *cmd, void *data)
1013{
1014 struct cmd_lookup *match = data;
1015
1016 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1017
1018 list_del(&cmd->list);
1019
1020 if (match->sk == NULL) {
1021 match->sk = cmd->sk;
1022 sock_hold(match->sk);
1023 }
1024
1025 mgmt_pending_free(cmd);
1026}
1027
1028static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1029{
1030 u8 *status = data;
1031
1032 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1033 mgmt_pending_remove(cmd);
1034}
1035
Johan Hedberge6fe7982013-10-02 15:45:22 +03001036static u8 mgmt_bredr_support(struct hci_dev *hdev)
1037{
1038 if (!lmp_bredr_capable(hdev))
1039 return MGMT_STATUS_NOT_SUPPORTED;
1040 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1041 return MGMT_STATUS_REJECTED;
1042 else
1043 return MGMT_STATUS_SUCCESS;
1044}
1045
1046static u8 mgmt_le_support(struct hci_dev *hdev)
1047{
1048 if (!lmp_le_capable(hdev))
1049 return MGMT_STATUS_NOT_SUPPORTED;
1050 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1051 return MGMT_STATUS_REJECTED;
1052 else
1053 return MGMT_STATUS_SUCCESS;
1054}
1055
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001056static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1057{
1058 struct pending_cmd *cmd;
1059 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001060 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001061 bool changed;
1062
1063 BT_DBG("status 0x%02x", status);
1064
1065 hci_dev_lock(hdev);
1066
1067 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1068 if (!cmd)
1069 goto unlock;
1070
1071 if (status) {
1072 u8 mgmt_err = mgmt_status(status);
1073 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001074 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001075 goto remove_cmd;
1076 }
1077
1078 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001079 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001080 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1081 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001082
1083 if (hdev->discov_timeout > 0) {
1084 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1085 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1086 to);
1087 }
1088 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001089 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1090 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001091 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001092
1093 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1094
1095 if (changed)
1096 new_settings(hdev, cmd->sk);
1097
Marcel Holtmann970ba522013-10-15 06:33:57 -07001098 /* When the discoverable mode gets changed, make sure
1099 * that class of device has the limited discoverable
1100 * bit correctly set.
1101 */
1102 hci_req_init(&req, hdev);
1103 update_class(&req);
1104 hci_req_run(&req, NULL);
1105
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001106remove_cmd:
1107 mgmt_pending_remove(cmd);
1108
1109unlock:
1110 hci_dev_unlock(hdev);
1111}
1112
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001113static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001114 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001115{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001116 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001117 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001118 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001119 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001120 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001121 int err;
1122
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001123 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001124
Johan Hedberge6fe7982013-10-02 15:45:22 +03001125 status = mgmt_bredr_support(hdev);
1126 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001127 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001128 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001129
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001130 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga7e80f22013-01-09 16:05:19 +02001131 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1132 MGMT_STATUS_INVALID_PARAMS);
1133
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001134 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001135
1136 /* Disabling discoverable requires that no timeout is set,
1137 * and enabling limited discoverable requires a timeout.
1138 */
1139 if ((cp->val == 0x00 && timeout > 0) ||
1140 (cp->val == 0x02 && timeout == 0))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001141 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001142 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001143
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001144 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001145
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001146 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001147 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001148 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001149 goto failed;
1150 }
1151
1152 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001153 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001154 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001155 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001156 goto failed;
1157 }
1158
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001159 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001160 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001161 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001162 goto failed;
1163 }
1164
1165 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001166 bool changed = false;
1167
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001168 /* Setting limited discoverable when powered off is
1169 * not a valid operation since it requires a timeout
1170 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1171 */
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001172 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1173 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1174 changed = true;
1175 }
1176
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001177 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001178 if (err < 0)
1179 goto failed;
1180
1181 if (changed)
1182 err = new_settings(hdev, sk);
1183
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001184 goto failed;
1185 }
1186
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001187 /* If the current mode is the same, then just update the timeout
1188 * value with the new value. And if only the timeout gets updated,
1189 * then no need for any HCI transactions.
1190 */
1191 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) &&
1192 (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE,
1193 &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001194 cancel_delayed_work(&hdev->discov_off);
1195 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001196
Marcel Holtmann36261542013-10-15 08:28:51 -07001197 if (cp->val && hdev->discov_timeout > 0) {
1198 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001199 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001200 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001201 }
1202
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001203 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001204 goto failed;
1205 }
1206
1207 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1208 if (!cmd) {
1209 err = -ENOMEM;
1210 goto failed;
1211 }
1212
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001213 /* Cancel any potential discoverable timeout that might be
1214 * still active and store new timeout value. The arming of
1215 * the timeout happens in the complete handler.
1216 */
1217 cancel_delayed_work(&hdev->discov_off);
1218 hdev->discov_timeout = timeout;
1219
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001220 hci_req_init(&req, hdev);
1221
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001222 scan = SCAN_PAGE;
1223
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001224 if (cp->val) {
1225 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001226
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001227 if (cp->val == 0x02) {
1228 /* Limited discoverable mode */
1229 set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1230
1231 hci_cp.num_iac = 2;
1232 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1233 hci_cp.iac_lap[1] = 0x8b;
1234 hci_cp.iac_lap[2] = 0x9e;
1235 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1236 hci_cp.iac_lap[4] = 0x8b;
1237 hci_cp.iac_lap[5] = 0x9e;
1238 } else {
1239 /* General discoverable mode */
1240 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1241
1242 hci_cp.num_iac = 1;
1243 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1244 hci_cp.iac_lap[1] = 0x8b;
1245 hci_cp.iac_lap[2] = 0x9e;
1246 }
1247
1248 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1249 (hci_cp.num_iac * 3) + 1, &hci_cp);
1250
1251 scan |= SCAN_INQUIRY;
1252 } else {
1253 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1254 }
1255
1256 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001257
1258 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001259 if (err < 0)
1260 mgmt_pending_remove(cmd);
1261
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001262failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001263 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001264 return err;
1265}
1266
Johan Hedberg406d7802013-03-15 17:07:09 -05001267static void write_fast_connectable(struct hci_request *req, bool enable)
1268{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001269 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001270 struct hci_cp_write_page_scan_activity acp;
1271 u8 type;
1272
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001273 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1274 return;
1275
Johan Hedberg406d7802013-03-15 17:07:09 -05001276 if (enable) {
1277 type = PAGE_SCAN_TYPE_INTERLACED;
1278
1279 /* 160 msec page scan interval */
1280 acp.interval = __constant_cpu_to_le16(0x0100);
1281 } else {
1282 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1283
1284 /* default 1.28 sec page scan */
1285 acp.interval = __constant_cpu_to_le16(0x0800);
1286 }
1287
1288 acp.window = __constant_cpu_to_le16(0x0012);
1289
Johan Hedbergbd98b992013-03-15 17:07:13 -05001290 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1291 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1292 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1293 sizeof(acp), &acp);
1294
1295 if (hdev->page_scan_type != type)
1296 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001297}
1298
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001299static u8 get_adv_type(struct hci_dev *hdev)
1300{
1301 struct pending_cmd *cmd;
1302 bool connectable;
1303
1304 /* If there's a pending mgmt command the flag will not yet have
1305 * it's final value, so check for this first.
1306 */
1307 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1308 if (cmd) {
1309 struct mgmt_mode *cp = cmd->param;
1310 connectable = !!cp->val;
1311 } else {
1312 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1313 }
1314
1315 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1316}
1317
Johan Hedberg95c66e72013-10-14 16:20:06 +03001318static void enable_advertising(struct hci_request *req)
1319{
1320 struct hci_dev *hdev = req->hdev;
1321 struct hci_cp_le_set_adv_param cp;
1322 u8 enable = 0x01;
1323
1324 memset(&cp, 0, sizeof(cp));
1325 cp.min_interval = __constant_cpu_to_le16(0x0800);
1326 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001327 cp.type = get_adv_type(hdev);
Marcel Holtmann79830f62013-10-18 16:38:09 -07001328 cp.own_address_type = hdev->own_addr_type;
Johan Hedberg95c66e72013-10-14 16:20:06 +03001329 cp.channel_map = 0x07;
1330
1331 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1332
1333 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1334}
1335
1336static void disable_advertising(struct hci_request *req)
1337{
1338 u8 enable = 0x00;
1339
1340 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1341}
1342
Johan Hedberg2b76f452013-03-15 17:07:04 -05001343static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1344{
1345 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001346 struct mgmt_mode *cp;
1347 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001348
1349 BT_DBG("status 0x%02x", status);
1350
1351 hci_dev_lock(hdev);
1352
1353 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1354 if (!cmd)
1355 goto unlock;
1356
Johan Hedberg37438c12013-10-14 16:20:05 +03001357 if (status) {
1358 u8 mgmt_err = mgmt_status(status);
1359 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1360 goto remove_cmd;
1361 }
1362
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001363 cp = cmd->param;
1364 if (cp->val)
1365 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1366 else
1367 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1368
Johan Hedberg2b76f452013-03-15 17:07:04 -05001369 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1370
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001371 if (changed)
1372 new_settings(hdev, cmd->sk);
1373
Johan Hedberg37438c12013-10-14 16:20:05 +03001374remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001375 mgmt_pending_remove(cmd);
1376
1377unlock:
1378 hci_dev_unlock(hdev);
1379}
1380
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001381static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001382 u16 len)
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001383{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001384 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001385 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001386 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001387 u8 scan;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001388 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001389
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001390 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001391
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001392 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1393 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001394 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001395 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001396
Johan Hedberga7e80f22013-01-09 16:05:19 +02001397 if (cp->val != 0x00 && cp->val != 0x01)
1398 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1399 MGMT_STATUS_INVALID_PARAMS);
1400
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001401 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001402
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001403 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001404 bool changed = false;
1405
1406 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1407 changed = true;
1408
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001409 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001410 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001411 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001412 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1413 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1414 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001415
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001416 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001417 if (err < 0)
1418 goto failed;
1419
1420 if (changed)
1421 err = new_settings(hdev, sk);
1422
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001423 goto failed;
1424 }
1425
1426 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001427 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001428 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001429 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001430 goto failed;
1431 }
1432
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001433 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1434 if (!cmd) {
1435 err = -ENOMEM;
1436 goto failed;
1437 }
1438
Johan Hedberg2b76f452013-03-15 17:07:04 -05001439 hci_req_init(&req, hdev);
1440
Johan Hedberg9b742462013-10-14 16:20:03 +03001441 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) &&
1442 cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001443 if (cp->val) {
1444 scan = SCAN_PAGE;
1445 } else {
1446 scan = 0;
1447
1448 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001449 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001450 cancel_delayed_work(&hdev->discov_off);
1451 }
1452
1453 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1454 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001455
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001456 /* If we're going from non-connectable to connectable or
1457 * vice-versa when fast connectable is enabled ensure that fast
1458 * connectable gets disabled. write_fast_connectable won't do
1459 * anything if the page scan parameters are already what they
1460 * should be.
1461 */
1462 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001463 write_fast_connectable(&req, false);
1464
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001465 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1466 hci_conn_num(hdev, LE_LINK) == 0) {
1467 disable_advertising(&req);
1468 enable_advertising(&req);
1469 }
1470
Johan Hedberg2b76f452013-03-15 17:07:04 -05001471 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001472 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001473 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001474 if (err == -ENODATA)
1475 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE,
1476 hdev);
1477 goto failed;
1478 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001479
1480failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001481 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001482 return err;
1483}
1484
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001485static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001486 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001487{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001488 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001489 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001490 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001491
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001492 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001493
Johan Hedberga7e80f22013-01-09 16:05:19 +02001494 if (cp->val != 0x00 && cp->val != 0x01)
1495 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1496 MGMT_STATUS_INVALID_PARAMS);
1497
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001498 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001499
1500 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001501 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001502 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001503 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001504
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001505 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001506 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001507 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001508
Marcel Holtmann55594352013-10-06 16:11:57 -07001509 if (changed)
1510 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001511
Marcel Holtmann55594352013-10-06 16:11:57 -07001512unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001513 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001514 return err;
1515}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001516
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001517static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1518 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001519{
1520 struct mgmt_mode *cp = data;
1521 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001522 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001523 int err;
1524
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001525 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001526
Johan Hedberge6fe7982013-10-02 15:45:22 +03001527 status = mgmt_bredr_support(hdev);
1528 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001529 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001530 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001531
Johan Hedberga7e80f22013-01-09 16:05:19 +02001532 if (cp->val != 0x00 && cp->val != 0x01)
1533 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1534 MGMT_STATUS_INVALID_PARAMS);
1535
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001536 hci_dev_lock(hdev);
1537
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001538 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001539 bool changed = false;
1540
1541 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001542 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001543 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1544 changed = true;
1545 }
1546
1547 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1548 if (err < 0)
1549 goto failed;
1550
1551 if (changed)
1552 err = new_settings(hdev, sk);
1553
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001554 goto failed;
1555 }
1556
1557 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001558 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001559 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001560 goto failed;
1561 }
1562
1563 val = !!cp->val;
1564
1565 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1566 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1567 goto failed;
1568 }
1569
1570 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1571 if (!cmd) {
1572 err = -ENOMEM;
1573 goto failed;
1574 }
1575
1576 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1577 if (err < 0) {
1578 mgmt_pending_remove(cmd);
1579 goto failed;
1580 }
1581
1582failed:
1583 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001584 return err;
1585}
1586
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001587static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001588{
1589 struct mgmt_mode *cp = data;
1590 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001591 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001592 int err;
1593
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001594 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001595
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001596 status = mgmt_bredr_support(hdev);
1597 if (status)
1598 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1599
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001600 if (!lmp_ssp_capable(hdev))
1601 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1602 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001603
Johan Hedberga7e80f22013-01-09 16:05:19 +02001604 if (cp->val != 0x00 && cp->val != 0x01)
1605 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1606 MGMT_STATUS_INVALID_PARAMS);
1607
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001608 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001609
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001610 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001611 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001612
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001613 if (cp->val) {
1614 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1615 &hdev->dev_flags);
1616 } else {
1617 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1618 &hdev->dev_flags);
1619 if (!changed)
1620 changed = test_and_clear_bit(HCI_HS_ENABLED,
1621 &hdev->dev_flags);
1622 else
1623 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001624 }
1625
1626 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1627 if (err < 0)
1628 goto failed;
1629
1630 if (changed)
1631 err = new_settings(hdev, sk);
1632
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001633 goto failed;
1634 }
1635
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001636 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1637 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001638 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1639 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001640 goto failed;
1641 }
1642
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001643 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001644 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1645 goto failed;
1646 }
1647
1648 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1649 if (!cmd) {
1650 err = -ENOMEM;
1651 goto failed;
1652 }
1653
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001654 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001655 if (err < 0) {
1656 mgmt_pending_remove(cmd);
1657 goto failed;
1658 }
1659
1660failed:
1661 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001662 return err;
1663}
1664
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001665static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001666{
1667 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001668 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001669 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001670 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001671
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001672 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001673
Johan Hedberge6fe7982013-10-02 15:45:22 +03001674 status = mgmt_bredr_support(hdev);
1675 if (status)
1676 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001677
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001678 if (!lmp_ssp_capable(hdev))
1679 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1680 MGMT_STATUS_NOT_SUPPORTED);
1681
1682 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1683 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1684 MGMT_STATUS_REJECTED);
1685
Johan Hedberga7e80f22013-01-09 16:05:19 +02001686 if (cp->val != 0x00 && cp->val != 0x01)
1687 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1688 MGMT_STATUS_INVALID_PARAMS);
1689
Marcel Holtmannee392692013-10-01 22:59:23 -07001690 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001691
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001692 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001693 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001694 } else {
1695 if (hdev_is_powered(hdev)) {
1696 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1697 MGMT_STATUS_REJECTED);
1698 goto unlock;
1699 }
1700
Marcel Holtmannee392692013-10-01 22:59:23 -07001701 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001702 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001703
1704 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1705 if (err < 0)
1706 goto unlock;
1707
1708 if (changed)
1709 err = new_settings(hdev, sk);
1710
1711unlock:
1712 hci_dev_unlock(hdev);
1713 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001714}
1715
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001716static void le_enable_complete(struct hci_dev *hdev, u8 status)
1717{
1718 struct cmd_lookup match = { NULL, hdev };
1719
1720 if (status) {
1721 u8 mgmt_err = mgmt_status(status);
1722
1723 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1724 &mgmt_err);
1725 return;
1726 }
1727
1728 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1729
1730 new_settings(hdev, match.sk);
1731
1732 if (match.sk)
1733 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001734
1735 /* Make sure the controller has a good default for
1736 * advertising data. Restrict the update to when LE
1737 * has actually been enabled. During power on, the
1738 * update in powered_update_hci will take care of it.
1739 */
1740 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1741 struct hci_request req;
1742
1743 hci_dev_lock(hdev);
1744
1745 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001746 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07001747 update_scan_rsp_data(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001748 hci_req_run(&req, NULL);
1749
1750 hci_dev_unlock(hdev);
1751 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001752}
1753
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001754static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001755{
1756 struct mgmt_mode *cp = data;
1757 struct hci_cp_write_le_host_supported hci_cp;
1758 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001759 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001760 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001761 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001762
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001763 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001764
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001765 if (!lmp_le_capable(hdev))
1766 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1767 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001768
Johan Hedberga7e80f22013-01-09 16:05:19 +02001769 if (cp->val != 0x00 && cp->val != 0x01)
1770 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1771 MGMT_STATUS_INVALID_PARAMS);
1772
Johan Hedbergc73eee92013-04-19 18:35:21 +03001773 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001774 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001775 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1776 MGMT_STATUS_REJECTED);
1777
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001778 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001779
1780 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001781 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001782
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001783 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001784 bool changed = false;
1785
1786 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1787 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1788 changed = true;
1789 }
1790
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001791 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1792 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001793 changed = true;
1794 }
1795
Johan Hedberg06199cf2012-02-22 16:37:11 +02001796 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1797 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001798 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001799
1800 if (changed)
1801 err = new_settings(hdev, sk);
1802
Johan Hedberg1de028c2012-02-29 19:55:35 -08001803 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001804 }
1805
Johan Hedberg4375f102013-09-25 13:26:10 +03001806 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1807 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001808 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001809 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001810 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001811 }
1812
1813 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1814 if (!cmd) {
1815 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001816 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001817 }
1818
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001819 hci_req_init(&req, hdev);
1820
Johan Hedberg06199cf2012-02-22 16:37:11 +02001821 memset(&hci_cp, 0, sizeof(hci_cp));
1822
1823 if (val) {
1824 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001825 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001826 } else {
1827 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1828 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001829 }
1830
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001831 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1832 &hci_cp);
1833
1834 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301835 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001836 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001837
Johan Hedberg1de028c2012-02-29 19:55:35 -08001838unlock:
1839 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001840 return err;
1841}
1842
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001843/* This is a helper function to test for pending mgmt commands that can
1844 * cause CoD or EIR HCI commands. We can only allow one such pending
1845 * mgmt command at a time since otherwise we cannot easily track what
1846 * the current values are, will be, and based on that calculate if a new
1847 * HCI command needs to be sent and if yes with what value.
1848 */
1849static bool pending_eir_or_class(struct hci_dev *hdev)
1850{
1851 struct pending_cmd *cmd;
1852
1853 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1854 switch (cmd->opcode) {
1855 case MGMT_OP_ADD_UUID:
1856 case MGMT_OP_REMOVE_UUID:
1857 case MGMT_OP_SET_DEV_CLASS:
1858 case MGMT_OP_SET_POWERED:
1859 return true;
1860 }
1861 }
1862
1863 return false;
1864}
1865
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001866static const u8 bluetooth_base_uuid[] = {
1867 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1868 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1869};
1870
1871static u8 get_uuid_size(const u8 *uuid)
1872{
1873 u32 val;
1874
1875 if (memcmp(uuid, bluetooth_base_uuid, 12))
1876 return 128;
1877
1878 val = get_unaligned_le32(&uuid[12]);
1879 if (val > 0xffff)
1880 return 32;
1881
1882 return 16;
1883}
1884
Johan Hedberg92da6092013-03-15 17:06:55 -05001885static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1886{
1887 struct pending_cmd *cmd;
1888
1889 hci_dev_lock(hdev);
1890
1891 cmd = mgmt_pending_find(mgmt_op, hdev);
1892 if (!cmd)
1893 goto unlock;
1894
1895 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1896 hdev->dev_class, 3);
1897
1898 mgmt_pending_remove(cmd);
1899
1900unlock:
1901 hci_dev_unlock(hdev);
1902}
1903
1904static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1905{
1906 BT_DBG("status 0x%02x", status);
1907
1908 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1909}
1910
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001911static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001912{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001913 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001914 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001915 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001916 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001917 int err;
1918
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001919 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001920
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001921 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001922
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001923 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001924 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001925 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001926 goto failed;
1927 }
1928
Andre Guedes92c4c202012-06-07 19:05:44 -03001929 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001930 if (!uuid) {
1931 err = -ENOMEM;
1932 goto failed;
1933 }
1934
1935 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001936 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001937 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001938
Johan Hedbergde66aa62013-01-27 00:31:27 +02001939 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001940
Johan Hedberg890ea892013-03-15 17:06:52 -05001941 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001942
Johan Hedberg890ea892013-03-15 17:06:52 -05001943 update_class(&req);
1944 update_eir(&req);
1945
Johan Hedberg92da6092013-03-15 17:06:55 -05001946 err = hci_req_run(&req, add_uuid_complete);
1947 if (err < 0) {
1948 if (err != -ENODATA)
1949 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001950
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001951 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001952 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001953 goto failed;
1954 }
1955
1956 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001957 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001958 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001959 goto failed;
1960 }
1961
1962 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001963
1964failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001965 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001966 return err;
1967}
1968
Johan Hedberg24b78d02012-02-23 23:24:30 +02001969static bool enable_service_cache(struct hci_dev *hdev)
1970{
1971 if (!hdev_is_powered(hdev))
1972 return false;
1973
1974 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001975 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1976 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001977 return true;
1978 }
1979
1980 return false;
1981}
1982
Johan Hedberg92da6092013-03-15 17:06:55 -05001983static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1984{
1985 BT_DBG("status 0x%02x", status);
1986
1987 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1988}
1989
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001990static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001991 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001992{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001993 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001994 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001995 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001996 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 -05001997 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001998 int err, found;
1999
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002000 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002001
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002002 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002003
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002004 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002005 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002006 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002007 goto unlock;
2008 }
2009
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002010 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
2011 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002012
Johan Hedberg24b78d02012-02-23 23:24:30 +02002013 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002014 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002015 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002016 goto unlock;
2017 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002018
Johan Hedberg9246a862012-02-23 21:33:16 +02002019 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002020 }
2021
2022 found = 0;
2023
Johan Hedberg056341c2013-01-27 00:31:30 +02002024 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002025 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2026 continue;
2027
2028 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002029 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002030 found++;
2031 }
2032
2033 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002034 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002035 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002036 goto unlock;
2037 }
2038
Johan Hedberg9246a862012-02-23 21:33:16 +02002039update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002040 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002041
Johan Hedberg890ea892013-03-15 17:06:52 -05002042 update_class(&req);
2043 update_eir(&req);
2044
Johan Hedberg92da6092013-03-15 17:06:55 -05002045 err = hci_req_run(&req, remove_uuid_complete);
2046 if (err < 0) {
2047 if (err != -ENODATA)
2048 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002049
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002050 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002051 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002052 goto unlock;
2053 }
2054
2055 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002056 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002057 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002058 goto unlock;
2059 }
2060
2061 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002062
2063unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002064 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002065 return err;
2066}
2067
Johan Hedberg92da6092013-03-15 17:06:55 -05002068static void set_class_complete(struct hci_dev *hdev, u8 status)
2069{
2070 BT_DBG("status 0x%02x", status);
2071
2072 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2073}
2074
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002075static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002076 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002077{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002078 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002079 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002080 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002081 int err;
2082
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002083 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002084
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002085 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002086 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2087 MGMT_STATUS_NOT_SUPPORTED);
2088
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002089 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002090
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002091 if (pending_eir_or_class(hdev)) {
2092 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2093 MGMT_STATUS_BUSY);
2094 goto unlock;
2095 }
2096
2097 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2098 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2099 MGMT_STATUS_INVALID_PARAMS);
2100 goto unlock;
2101 }
2102
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002103 hdev->major_class = cp->major;
2104 hdev->minor_class = cp->minor;
2105
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002106 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002107 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002108 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002109 goto unlock;
2110 }
2111
Johan Hedberg890ea892013-03-15 17:06:52 -05002112 hci_req_init(&req, hdev);
2113
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002114 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002115 hci_dev_unlock(hdev);
2116 cancel_delayed_work_sync(&hdev->service_cache);
2117 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002118 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002119 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002120
Johan Hedberg890ea892013-03-15 17:06:52 -05002121 update_class(&req);
2122
Johan Hedberg92da6092013-03-15 17:06:55 -05002123 err = hci_req_run(&req, set_class_complete);
2124 if (err < 0) {
2125 if (err != -ENODATA)
2126 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002127
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002128 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002129 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002130 goto unlock;
2131 }
2132
2133 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002134 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002135 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002136 goto unlock;
2137 }
2138
2139 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002140
Johan Hedbergb5235a62012-02-21 14:32:24 +02002141unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002142 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002143 return err;
2144}
2145
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002146static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002147 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002148{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002149 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002150 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002151 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002152
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002153 BT_DBG("request for %s", hdev->name);
2154
2155 if (!lmp_bredr_capable(hdev))
2156 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2157 MGMT_STATUS_NOT_SUPPORTED);
2158
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002159 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002160
Johan Hedberg86742e12011-11-07 23:13:38 +02002161 expected_len = sizeof(*cp) + key_count *
2162 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002163 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002164 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002165 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002166 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002167 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002168 }
2169
Johan Hedberg4ae14302013-01-20 14:27:13 +02002170 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2171 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2172 MGMT_STATUS_INVALID_PARAMS);
2173
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002174 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002175 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002176
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002177 for (i = 0; i < key_count; i++) {
2178 struct mgmt_link_key_info *key = &cp->keys[i];
2179
2180 if (key->addr.type != BDADDR_BREDR)
2181 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2182 MGMT_STATUS_INVALID_PARAMS);
2183 }
2184
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002185 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002186
2187 hci_link_keys_clear(hdev);
2188
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002189 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002190 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002191 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002192 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002193
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002194 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002195 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002196
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002197 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002198 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002199 }
2200
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002201 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002202
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002203 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002204
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002205 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002206}
2207
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002208static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002209 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002210{
2211 struct mgmt_ev_device_unpaired ev;
2212
2213 bacpy(&ev.addr.bdaddr, bdaddr);
2214 ev.addr.type = addr_type;
2215
2216 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002217 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002218}
2219
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002220static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002221 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002222{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002223 struct mgmt_cp_unpair_device *cp = data;
2224 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002225 struct hci_cp_disconnect dc;
2226 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002227 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002228 int err;
2229
Johan Hedberga8a1d192011-11-10 15:54:38 +02002230 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002231 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2232 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002233
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002234 if (!bdaddr_type_is_valid(cp->addr.type))
2235 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2236 MGMT_STATUS_INVALID_PARAMS,
2237 &rp, sizeof(rp));
2238
Johan Hedberg118da702013-01-20 14:27:20 +02002239 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2240 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2241 MGMT_STATUS_INVALID_PARAMS,
2242 &rp, sizeof(rp));
2243
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002244 hci_dev_lock(hdev);
2245
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002246 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002247 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002248 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002249 goto unlock;
2250 }
2251
Andre Guedes591f47f2012-04-24 21:02:49 -03002252 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02002253 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
2254 else
2255 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002256
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002257 if (err < 0) {
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_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002260 goto unlock;
2261 }
2262
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002263 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002264 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002265 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002266 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002267 else
2268 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002269 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002270 } else {
2271 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002272 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002273
Johan Hedberga8a1d192011-11-10 15:54:38 +02002274 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002275 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002276 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002277 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002278 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002279 }
2280
Johan Hedberg124f6e32012-02-09 13:50:12 +02002281 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002282 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002283 if (!cmd) {
2284 err = -ENOMEM;
2285 goto unlock;
2286 }
2287
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002288 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002289 dc.reason = 0x13; /* Remote User Terminated Connection */
2290 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2291 if (err < 0)
2292 mgmt_pending_remove(cmd);
2293
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002294unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002295 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002296 return err;
2297}
2298
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002299static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002300 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002301{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002302 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002303 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002304 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002305 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002306 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002307 int err;
2308
2309 BT_DBG("");
2310
Johan Hedberg06a63b12013-01-20 14:27:21 +02002311 memset(&rp, 0, sizeof(rp));
2312 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2313 rp.addr.type = cp->addr.type;
2314
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002315 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002316 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2317 MGMT_STATUS_INVALID_PARAMS,
2318 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002319
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002320 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002321
2322 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002323 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2324 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002325 goto failed;
2326 }
2327
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002328 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002329 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2330 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002331 goto failed;
2332 }
2333
Andre Guedes591f47f2012-04-24 21:02:49 -03002334 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002335 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2336 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002337 else
2338 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002339
Vishal Agarwalf9607272012-06-13 05:32:43 +05302340 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002341 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2342 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002343 goto failed;
2344 }
2345
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002346 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002347 if (!cmd) {
2348 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002349 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002350 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002351
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002352 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002353 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002354
2355 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2356 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002357 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002358
2359failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002360 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002361 return err;
2362}
2363
Andre Guedes57c14772012-04-24 21:02:50 -03002364static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002365{
2366 switch (link_type) {
2367 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002368 switch (addr_type) {
2369 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002370 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002371
Johan Hedberg48264f02011-11-09 13:58:58 +02002372 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002373 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002374 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002375 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002376
Johan Hedberg4c659c32011-11-07 23:13:39 +02002377 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002378 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002379 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002380 }
2381}
2382
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002383static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2384 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002385{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002386 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002387 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002388 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002389 int err;
2390 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002391
2392 BT_DBG("");
2393
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002394 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002395
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002396 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002397 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002398 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002399 goto unlock;
2400 }
2401
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002402 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002403 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2404 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002405 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002406 }
2407
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002408 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002409 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002410 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002411 err = -ENOMEM;
2412 goto unlock;
2413 }
2414
Johan Hedberg2784eb42011-01-21 13:56:35 +02002415 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002416 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002417 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2418 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002419 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002420 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002421 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002422 continue;
2423 i++;
2424 }
2425
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002426 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002427
Johan Hedberg4c659c32011-11-07 23:13:39 +02002428 /* Recalculate length in case of filtered SCO connections, etc */
2429 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002430
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002431 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002432 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002433
Johan Hedberga38528f2011-01-22 06:46:43 +02002434 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002435
2436unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002437 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002438 return err;
2439}
2440
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002441static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002442 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002443{
2444 struct pending_cmd *cmd;
2445 int err;
2446
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002447 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002448 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002449 if (!cmd)
2450 return -ENOMEM;
2451
Johan Hedbergd8457692012-02-17 14:24:57 +02002452 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002453 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002454 if (err < 0)
2455 mgmt_pending_remove(cmd);
2456
2457 return err;
2458}
2459
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002460static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002461 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002462{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002463 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002464 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002465 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002466 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002467 int err;
2468
2469 BT_DBG("");
2470
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002471 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002472
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002473 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002474 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002475 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002476 goto failed;
2477 }
2478
Johan Hedbergd8457692012-02-17 14:24:57 +02002479 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002480 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002481 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002482 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002483 goto failed;
2484 }
2485
2486 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002487 struct mgmt_cp_pin_code_neg_reply ncp;
2488
2489 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002490
2491 BT_ERR("PIN code is not 16 bytes long");
2492
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002493 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002494 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002495 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002496 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002497
2498 goto failed;
2499 }
2500
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002501 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002502 if (!cmd) {
2503 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002504 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002505 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002506
Johan Hedbergd8457692012-02-17 14:24:57 +02002507 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002508 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002509 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002510
2511 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2512 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002513 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002514
2515failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002516 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002517 return err;
2518}
2519
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002520static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2521 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002522{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002523 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002524
2525 BT_DBG("");
2526
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002527 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002528
2529 hdev->io_capability = cp->io_capability;
2530
2531 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002532 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002533
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002534 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002535
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002536 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2537 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002538}
2539
Gustavo Padovan6039aa732012-05-23 04:04:18 -03002540static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002541{
2542 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002543 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002544
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002545 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002546 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2547 continue;
2548
Johan Hedberge9a416b2011-02-19 12:05:56 -03002549 if (cmd->user_data != conn)
2550 continue;
2551
2552 return cmd;
2553 }
2554
2555 return NULL;
2556}
2557
2558static void pairing_complete(struct pending_cmd *cmd, u8 status)
2559{
2560 struct mgmt_rp_pair_device rp;
2561 struct hci_conn *conn = cmd->user_data;
2562
Johan Hedbergba4e5642011-11-11 00:07:34 +02002563 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002564 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002565
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002566 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002567 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002568
2569 /* So we don't get further callbacks for this connection */
2570 conn->connect_cfm_cb = NULL;
2571 conn->security_cfm_cb = NULL;
2572 conn->disconn_cfm_cb = NULL;
2573
David Herrmann76a68ba2013-04-06 20:28:37 +02002574 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002575
Johan Hedberga664b5b2011-02-19 12:06:02 -03002576 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002577}
2578
2579static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2580{
2581 struct pending_cmd *cmd;
2582
2583 BT_DBG("status %u", status);
2584
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002585 cmd = find_pairing(conn);
2586 if (!cmd)
2587 BT_DBG("Unable to find a pending command");
2588 else
Johan Hedberge2113262012-02-18 15:20:03 +02002589 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002590}
2591
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302592static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2593{
2594 struct pending_cmd *cmd;
2595
2596 BT_DBG("status %u", status);
2597
2598 if (!status)
2599 return;
2600
2601 cmd = find_pairing(conn);
2602 if (!cmd)
2603 BT_DBG("Unable to find a pending command");
2604 else
2605 pairing_complete(cmd, mgmt_status(status));
2606}
2607
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002608static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002609 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002610{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002611 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002612 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002613 struct pending_cmd *cmd;
2614 u8 sec_level, auth_type;
2615 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002616 int err;
2617
2618 BT_DBG("");
2619
Szymon Jancf950a30e2013-01-18 12:48:07 +01002620 memset(&rp, 0, sizeof(rp));
2621 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2622 rp.addr.type = cp->addr.type;
2623
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002624 if (!bdaddr_type_is_valid(cp->addr.type))
2625 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2626 MGMT_STATUS_INVALID_PARAMS,
2627 &rp, sizeof(rp));
2628
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002629 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002630
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002631 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002632 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2633 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002634 goto unlock;
2635 }
2636
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002637 sec_level = BT_SECURITY_MEDIUM;
2638 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002639 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002640 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002641 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002642
Andre Guedes591f47f2012-04-24 21:02:49 -03002643 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002644 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2645 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002646 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002647 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2648 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002649
Ville Tervo30e76272011-02-22 16:10:53 -03002650 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002651 int status;
2652
2653 if (PTR_ERR(conn) == -EBUSY)
2654 status = MGMT_STATUS_BUSY;
2655 else
2656 status = MGMT_STATUS_CONNECT_FAILED;
2657
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002658 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002659 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002660 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002661 goto unlock;
2662 }
2663
2664 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002665 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002666 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002667 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002668 goto unlock;
2669 }
2670
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002671 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002672 if (!cmd) {
2673 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002674 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002675 goto unlock;
2676 }
2677
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002678 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002679 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002680 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302681 else
2682 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002683
Johan Hedberge9a416b2011-02-19 12:05:56 -03002684 conn->security_cfm_cb = pairing_complete_cb;
2685 conn->disconn_cfm_cb = pairing_complete_cb;
2686 conn->io_capability = cp->io_cap;
2687 cmd->user_data = conn;
2688
2689 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002690 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002691 pairing_complete(cmd, 0);
2692
2693 err = 0;
2694
2695unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002696 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002697 return err;
2698}
2699
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002700static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2701 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002702{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002703 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002704 struct pending_cmd *cmd;
2705 struct hci_conn *conn;
2706 int err;
2707
2708 BT_DBG("");
2709
Johan Hedberg28424702012-02-02 04:02:29 +02002710 hci_dev_lock(hdev);
2711
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002712 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002713 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002714 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002715 goto unlock;
2716 }
2717
Johan Hedberg28424702012-02-02 04:02:29 +02002718 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2719 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002720 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002721 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002722 goto unlock;
2723 }
2724
2725 conn = cmd->user_data;
2726
2727 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002728 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002729 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002730 goto unlock;
2731 }
2732
2733 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2734
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002735 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002736 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002737unlock:
2738 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002739 return err;
2740}
2741
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002742static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002743 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002744 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002745{
Johan Hedberga5c29682011-02-19 12:05:57 -03002746 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002747 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002748 int err;
2749
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002750 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002751
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002752 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002753 err = cmd_complete(sk, hdev->id, mgmt_op,
2754 MGMT_STATUS_NOT_POWERED, addr,
2755 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002756 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002757 }
2758
Johan Hedberg1707c602013-03-15 17:07:15 -05002759 if (addr->type == BDADDR_BREDR)
2760 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002761 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002762 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002763
Johan Hedberg272d90d2012-02-09 15:26:12 +02002764 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002765 err = cmd_complete(sk, hdev->id, mgmt_op,
2766 MGMT_STATUS_NOT_CONNECTED, addr,
2767 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002768 goto done;
2769 }
2770
Johan Hedberg1707c602013-03-15 17:07:15 -05002771 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002772 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002773 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002774
Brian Gix5fe57d92011-12-21 16:12:13 -08002775 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002776 err = cmd_complete(sk, hdev->id, mgmt_op,
2777 MGMT_STATUS_SUCCESS, addr,
2778 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002779 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002780 err = cmd_complete(sk, hdev->id, mgmt_op,
2781 MGMT_STATUS_FAILED, addr,
2782 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002783
Brian Gix47c15e22011-11-16 13:53:14 -08002784 goto done;
2785 }
2786
Johan Hedberg1707c602013-03-15 17:07:15 -05002787 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002788 if (!cmd) {
2789 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002790 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002791 }
2792
Brian Gix0df4c182011-11-16 13:53:13 -08002793 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002794 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2795 struct hci_cp_user_passkey_reply cp;
2796
Johan Hedberg1707c602013-03-15 17:07:15 -05002797 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002798 cp.passkey = passkey;
2799 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2800 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002801 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2802 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002803
Johan Hedberga664b5b2011-02-19 12:06:02 -03002804 if (err < 0)
2805 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002806
Brian Gix0df4c182011-11-16 13:53:13 -08002807done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002808 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002809 return err;
2810}
2811
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302812static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2813 void *data, u16 len)
2814{
2815 struct mgmt_cp_pin_code_neg_reply *cp = data;
2816
2817 BT_DBG("");
2818
Johan Hedberg1707c602013-03-15 17:07:15 -05002819 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302820 MGMT_OP_PIN_CODE_NEG_REPLY,
2821 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2822}
2823
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002824static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2825 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002826{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002827 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002828
2829 BT_DBG("");
2830
2831 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002832 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002833 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002834
Johan Hedberg1707c602013-03-15 17:07:15 -05002835 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002836 MGMT_OP_USER_CONFIRM_REPLY,
2837 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002838}
2839
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002840static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002841 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002842{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002843 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002844
2845 BT_DBG("");
2846
Johan Hedberg1707c602013-03-15 17:07:15 -05002847 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002848 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2849 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002850}
2851
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002852static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2853 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002854{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002855 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002856
2857 BT_DBG("");
2858
Johan Hedberg1707c602013-03-15 17:07:15 -05002859 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002860 MGMT_OP_USER_PASSKEY_REPLY,
2861 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002862}
2863
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002864static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002865 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002866{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002867 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002868
2869 BT_DBG("");
2870
Johan Hedberg1707c602013-03-15 17:07:15 -05002871 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002872 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2873 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002874}
2875
Johan Hedberg13928972013-03-15 17:07:00 -05002876static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002877{
Johan Hedberg13928972013-03-15 17:07:00 -05002878 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002879 struct hci_cp_write_local_name cp;
2880
Johan Hedberg13928972013-03-15 17:07:00 -05002881 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002882
Johan Hedberg890ea892013-03-15 17:06:52 -05002883 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002884}
2885
Johan Hedberg13928972013-03-15 17:07:00 -05002886static void set_name_complete(struct hci_dev *hdev, u8 status)
2887{
2888 struct mgmt_cp_set_local_name *cp;
2889 struct pending_cmd *cmd;
2890
2891 BT_DBG("status 0x%02x", status);
2892
2893 hci_dev_lock(hdev);
2894
2895 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2896 if (!cmd)
2897 goto unlock;
2898
2899 cp = cmd->param;
2900
2901 if (status)
2902 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2903 mgmt_status(status));
2904 else
2905 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2906 cp, sizeof(*cp));
2907
2908 mgmt_pending_remove(cmd);
2909
2910unlock:
2911 hci_dev_unlock(hdev);
2912}
2913
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002914static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002915 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002916{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002917 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002918 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002919 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002920 int err;
2921
2922 BT_DBG("");
2923
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002924 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002925
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002926 /* If the old values are the same as the new ones just return a
2927 * direct command complete event.
2928 */
2929 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2930 !memcmp(hdev->short_name, cp->short_name,
2931 sizeof(hdev->short_name))) {
2932 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2933 data, len);
2934 goto failed;
2935 }
2936
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002937 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002938
Johan Hedbergb5235a62012-02-21 14:32:24 +02002939 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002940 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002941
2942 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002943 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002944 if (err < 0)
2945 goto failed;
2946
2947 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002948 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002949
Johan Hedbergb5235a62012-02-21 14:32:24 +02002950 goto failed;
2951 }
2952
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002953 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002954 if (!cmd) {
2955 err = -ENOMEM;
2956 goto failed;
2957 }
2958
Johan Hedberg13928972013-03-15 17:07:00 -05002959 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2960
Johan Hedberg890ea892013-03-15 17:06:52 -05002961 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002962
2963 if (lmp_bredr_capable(hdev)) {
2964 update_name(&req);
2965 update_eir(&req);
2966 }
2967
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07002968 /* The name is stored in the scan response data and so
2969 * no need to udpate the advertising data here.
2970 */
Johan Hedberg3f985052013-03-15 17:07:02 -05002971 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07002972 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05002973
Johan Hedberg13928972013-03-15 17:07:00 -05002974 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002975 if (err < 0)
2976 mgmt_pending_remove(cmd);
2977
2978failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002979 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002980 return err;
2981}
2982
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002983static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002984 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002985{
Szymon Jancc35938b2011-03-22 13:12:21 +01002986 struct pending_cmd *cmd;
2987 int err;
2988
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002989 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002990
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002991 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002992
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002993 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002994 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002995 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002996 goto unlock;
2997 }
2998
Andre Guedes9a1a1992012-07-24 15:03:48 -03002999 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003000 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003001 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003002 goto unlock;
3003 }
3004
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003005 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003006 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003007 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003008 goto unlock;
3009 }
3010
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003011 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003012 if (!cmd) {
3013 err = -ENOMEM;
3014 goto unlock;
3015 }
3016
3017 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3018 if (err < 0)
3019 mgmt_pending_remove(cmd);
3020
3021unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003022 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003023 return err;
3024}
3025
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003026static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003027 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003028{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003029 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003030 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003031 int err;
3032
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003033 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003034
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003035 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003036
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003037 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003038 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01003039 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003040 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01003041 else
Szymon Janca6785be2012-12-13 15:11:21 +01003042 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003043
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003044 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003045 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003046
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003047 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003048 return err;
3049}
3050
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003051static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003052 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003053{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003054 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003055 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003056 int err;
3057
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003058 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003059
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003060 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003061
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003062 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003063 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003064 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003065 else
Szymon Janca6785be2012-12-13 15:11:21 +01003066 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003067
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003068 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003069 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003070
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003071 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003072 return err;
3073}
3074
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003075static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3076{
3077 struct pending_cmd *cmd;
3078 u8 type;
3079 int err;
3080
3081 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3082
3083 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3084 if (!cmd)
3085 return -ENOENT;
3086
3087 type = hdev->discovery.type;
3088
3089 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3090 &type, sizeof(type));
3091 mgmt_pending_remove(cmd);
3092
3093 return err;
3094}
3095
Andre Guedes7c307722013-04-30 15:29:28 -03003096static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3097{
3098 BT_DBG("status %d", status);
3099
3100 if (status) {
3101 hci_dev_lock(hdev);
3102 mgmt_start_discovery_failed(hdev, status);
3103 hci_dev_unlock(hdev);
3104 return;
3105 }
3106
3107 hci_dev_lock(hdev);
3108 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3109 hci_dev_unlock(hdev);
3110
3111 switch (hdev->discovery.type) {
3112 case DISCOV_TYPE_LE:
3113 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003114 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003115 break;
3116
3117 case DISCOV_TYPE_INTERLEAVED:
3118 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003119 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003120 break;
3121
3122 case DISCOV_TYPE_BREDR:
3123 break;
3124
3125 default:
3126 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3127 }
3128}
3129
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003130static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003131 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003132{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003133 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003134 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003135 struct hci_cp_le_set_scan_param param_cp;
3136 struct hci_cp_le_set_scan_enable enable_cp;
3137 struct hci_cp_inquiry inq_cp;
3138 struct hci_request req;
3139 /* General inquiry access code (GIAC) */
3140 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003141 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003142 int err;
3143
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003144 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003145
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003146 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003147
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003148 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003149 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003150 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003151 goto failed;
3152 }
3153
Andre Guedes642be6c2012-03-21 00:03:37 -03003154 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3155 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3156 MGMT_STATUS_BUSY);
3157 goto failed;
3158 }
3159
Johan Hedbergff9ef572012-01-04 14:23:45 +02003160 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003161 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003162 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003163 goto failed;
3164 }
3165
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003166 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003167 if (!cmd) {
3168 err = -ENOMEM;
3169 goto failed;
3170 }
3171
Andre Guedes4aab14e2012-02-17 20:39:36 -03003172 hdev->discovery.type = cp->type;
3173
Andre Guedes7c307722013-04-30 15:29:28 -03003174 hci_req_init(&req, hdev);
3175
Andre Guedes4aab14e2012-02-17 20:39:36 -03003176 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003177 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003178 status = mgmt_bredr_support(hdev);
3179 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003180 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003181 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003182 mgmt_pending_remove(cmd);
3183 goto failed;
3184 }
3185
Andre Guedes7c307722013-04-30 15:29:28 -03003186 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3187 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3188 MGMT_STATUS_BUSY);
3189 mgmt_pending_remove(cmd);
3190 goto failed;
3191 }
3192
3193 hci_inquiry_cache_flush(hdev);
3194
3195 memset(&inq_cp, 0, sizeof(inq_cp));
3196 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003197 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003198 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003199 break;
3200
3201 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003202 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003203 status = mgmt_le_support(hdev);
3204 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003205 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003206 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003207 mgmt_pending_remove(cmd);
3208 goto failed;
3209 }
3210
Andre Guedes7c307722013-04-30 15:29:28 -03003211 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003212 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003213 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3214 MGMT_STATUS_NOT_SUPPORTED);
3215 mgmt_pending_remove(cmd);
3216 goto failed;
3217 }
3218
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003219 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003220 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3221 MGMT_STATUS_REJECTED);
3222 mgmt_pending_remove(cmd);
3223 goto failed;
3224 }
3225
3226 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3227 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3228 MGMT_STATUS_BUSY);
3229 mgmt_pending_remove(cmd);
3230 goto failed;
3231 }
3232
3233 memset(&param_cp, 0, sizeof(param_cp));
3234 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003235 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3236 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmann79830f62013-10-18 16:38:09 -07003237 param_cp.own_address_type = hdev->own_addr_type;
Andre Guedes7c307722013-04-30 15:29:28 -03003238 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3239 &param_cp);
3240
3241 memset(&enable_cp, 0, sizeof(enable_cp));
3242 enable_cp.enable = LE_SCAN_ENABLE;
3243 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3244 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3245 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003246 break;
3247
Andre Guedesf39799f2012-02-17 20:39:35 -03003248 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003249 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3250 MGMT_STATUS_INVALID_PARAMS);
3251 mgmt_pending_remove(cmd);
3252 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003253 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003254
Andre Guedes7c307722013-04-30 15:29:28 -03003255 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003256 if (err < 0)
3257 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003258 else
3259 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003260
3261failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003262 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003263 return err;
3264}
3265
Andre Guedes1183fdc2013-04-30 15:29:35 -03003266static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3267{
3268 struct pending_cmd *cmd;
3269 int err;
3270
3271 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3272 if (!cmd)
3273 return -ENOENT;
3274
3275 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3276 &hdev->discovery.type, sizeof(hdev->discovery.type));
3277 mgmt_pending_remove(cmd);
3278
3279 return err;
3280}
3281
Andre Guedes0e05bba2013-04-30 15:29:33 -03003282static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3283{
3284 BT_DBG("status %d", status);
3285
3286 hci_dev_lock(hdev);
3287
3288 if (status) {
3289 mgmt_stop_discovery_failed(hdev, status);
3290 goto unlock;
3291 }
3292
3293 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3294
3295unlock:
3296 hci_dev_unlock(hdev);
3297}
3298
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003299static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003300 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003301{
Johan Hedbergd9306502012-02-20 23:25:18 +02003302 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003303 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003304 struct hci_cp_remote_name_req_cancel cp;
3305 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003306 struct hci_request req;
3307 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003308 int err;
3309
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003310 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003311
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003312 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003313
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003314 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003315 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003316 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3317 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003318 goto unlock;
3319 }
3320
3321 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003322 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003323 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3324 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003325 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003326 }
3327
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003328 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003329 if (!cmd) {
3330 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003331 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003332 }
3333
Andre Guedes0e05bba2013-04-30 15:29:33 -03003334 hci_req_init(&req, hdev);
3335
Andre Guedese0d9727e2012-03-20 15:15:36 -03003336 switch (hdev->discovery.state) {
3337 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003338 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3339 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3340 } else {
3341 cancel_delayed_work(&hdev->le_scan_disable);
3342
3343 memset(&enable_cp, 0, sizeof(enable_cp));
3344 enable_cp.enable = LE_SCAN_DISABLE;
3345 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3346 sizeof(enable_cp), &enable_cp);
3347 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003348
Andre Guedese0d9727e2012-03-20 15:15:36 -03003349 break;
3350
3351 case DISCOVERY_RESOLVING:
3352 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003353 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003354 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003355 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003356 err = cmd_complete(sk, hdev->id,
3357 MGMT_OP_STOP_DISCOVERY, 0,
3358 &mgmt_cp->type,
3359 sizeof(mgmt_cp->type));
3360 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3361 goto unlock;
3362 }
3363
3364 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003365 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3366 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003367
3368 break;
3369
3370 default:
3371 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003372
3373 mgmt_pending_remove(cmd);
3374 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3375 MGMT_STATUS_FAILED, &mgmt_cp->type,
3376 sizeof(mgmt_cp->type));
3377 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003378 }
3379
Andre Guedes0e05bba2013-04-30 15:29:33 -03003380 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003381 if (err < 0)
3382 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003383 else
3384 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003385
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003386unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003387 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003388 return err;
3389}
3390
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003391static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003392 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003393{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003394 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003395 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003396 int err;
3397
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003398 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003399
Johan Hedberg561aafb2012-01-04 13:31:59 +02003400 hci_dev_lock(hdev);
3401
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003402 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003403 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003404 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003405 goto failed;
3406 }
3407
Johan Hedberga198e7b2012-02-17 14:27:06 +02003408 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003409 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003410 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003411 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003412 goto failed;
3413 }
3414
3415 if (cp->name_known) {
3416 e->name_state = NAME_KNOWN;
3417 list_del(&e->list);
3418 } else {
3419 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003420 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003421 }
3422
Johan Hedberge3846622013-01-09 15:29:33 +02003423 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3424 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003425
3426failed:
3427 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003428 return err;
3429}
3430
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003431static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003432 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003433{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003434 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003435 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003436 int err;
3437
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003438 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003439
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003440 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003441 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3442 MGMT_STATUS_INVALID_PARAMS,
3443 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003444
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003445 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003446
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003447 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003448 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003449 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003450 else
Szymon Janca6785be2012-12-13 15:11:21 +01003451 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003452
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003453 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003454 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003455
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003456 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003457
3458 return err;
3459}
3460
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003461static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003462 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003463{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003464 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003465 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003466 int err;
3467
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003468 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003469
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003470 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003471 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3472 MGMT_STATUS_INVALID_PARAMS,
3473 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003474
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003475 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003476
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003477 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003478 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003479 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003480 else
Szymon Janca6785be2012-12-13 15:11:21 +01003481 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003482
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003483 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003484 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003485
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003486 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003487
3488 return err;
3489}
3490
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003491static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3492 u16 len)
3493{
3494 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003495 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003496 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003497 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003498
3499 BT_DBG("%s", hdev->name);
3500
Szymon Jancc72d4b82012-03-16 16:02:57 +01003501 source = __le16_to_cpu(cp->source);
3502
3503 if (source > 0x0002)
3504 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3505 MGMT_STATUS_INVALID_PARAMS);
3506
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003507 hci_dev_lock(hdev);
3508
Szymon Jancc72d4b82012-03-16 16:02:57 +01003509 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003510 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3511 hdev->devid_product = __le16_to_cpu(cp->product);
3512 hdev->devid_version = __le16_to_cpu(cp->version);
3513
3514 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3515
Johan Hedberg890ea892013-03-15 17:06:52 -05003516 hci_req_init(&req, hdev);
3517 update_eir(&req);
3518 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003519
3520 hci_dev_unlock(hdev);
3521
3522 return err;
3523}
3524
Johan Hedberg4375f102013-09-25 13:26:10 +03003525static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3526{
3527 struct cmd_lookup match = { NULL, hdev };
3528
3529 if (status) {
3530 u8 mgmt_err = mgmt_status(status);
3531
3532 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3533 cmd_status_rsp, &mgmt_err);
3534 return;
3535 }
3536
3537 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3538 &match);
3539
3540 new_settings(hdev, match.sk);
3541
3542 if (match.sk)
3543 sock_put(match.sk);
3544}
3545
Marcel Holtmann21b51872013-10-10 09:47:53 -07003546static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3547 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003548{
3549 struct mgmt_mode *cp = data;
3550 struct pending_cmd *cmd;
3551 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003552 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003553 int err;
3554
3555 BT_DBG("request for %s", hdev->name);
3556
Johan Hedberge6fe7982013-10-02 15:45:22 +03003557 status = mgmt_le_support(hdev);
3558 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003559 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003560 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003561
3562 if (cp->val != 0x00 && cp->val != 0x01)
3563 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3564 MGMT_STATUS_INVALID_PARAMS);
3565
3566 hci_dev_lock(hdev);
3567
3568 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003569 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003570
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003571 /* The following conditions are ones which mean that we should
3572 * not do any HCI communication but directly send a mgmt
3573 * response to user space (after toggling the flag if
3574 * necessary).
3575 */
3576 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003577 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003578 bool changed = false;
3579
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003580 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3581 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003582 changed = true;
3583 }
3584
3585 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3586 if (err < 0)
3587 goto unlock;
3588
3589 if (changed)
3590 err = new_settings(hdev, sk);
3591
3592 goto unlock;
3593 }
3594
3595 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3596 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3597 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3598 MGMT_STATUS_BUSY);
3599 goto unlock;
3600 }
3601
3602 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3603 if (!cmd) {
3604 err = -ENOMEM;
3605 goto unlock;
3606 }
3607
3608 hci_req_init(&req, hdev);
3609
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003610 if (val)
3611 enable_advertising(&req);
3612 else
3613 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003614
3615 err = hci_req_run(&req, set_advertising_complete);
3616 if (err < 0)
3617 mgmt_pending_remove(cmd);
3618
3619unlock:
3620 hci_dev_unlock(hdev);
3621 return err;
3622}
3623
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003624static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3625 void *data, u16 len)
3626{
3627 struct mgmt_cp_set_static_address *cp = data;
3628 int err;
3629
3630 BT_DBG("%s", hdev->name);
3631
Marcel Holtmann62af4442013-10-02 22:10:32 -07003632 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003633 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003634 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003635
3636 if (hdev_is_powered(hdev))
3637 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3638 MGMT_STATUS_REJECTED);
3639
3640 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3641 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3642 return cmd_status(sk, hdev->id,
3643 MGMT_OP_SET_STATIC_ADDRESS,
3644 MGMT_STATUS_INVALID_PARAMS);
3645
3646 /* Two most significant bits shall be set */
3647 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3648 return cmd_status(sk, hdev->id,
3649 MGMT_OP_SET_STATIC_ADDRESS,
3650 MGMT_STATUS_INVALID_PARAMS);
3651 }
3652
3653 hci_dev_lock(hdev);
3654
3655 bacpy(&hdev->static_addr, &cp->bdaddr);
3656
3657 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3658
3659 hci_dev_unlock(hdev);
3660
3661 return err;
3662}
3663
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003664static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3665 void *data, u16 len)
3666{
3667 struct mgmt_cp_set_scan_params *cp = data;
3668 __u16 interval, window;
3669 int err;
3670
3671 BT_DBG("%s", hdev->name);
3672
3673 if (!lmp_le_capable(hdev))
3674 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3675 MGMT_STATUS_NOT_SUPPORTED);
3676
3677 interval = __le16_to_cpu(cp->interval);
3678
3679 if (interval < 0x0004 || interval > 0x4000)
3680 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3681 MGMT_STATUS_INVALID_PARAMS);
3682
3683 window = __le16_to_cpu(cp->window);
3684
3685 if (window < 0x0004 || window > 0x4000)
3686 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3687 MGMT_STATUS_INVALID_PARAMS);
3688
Marcel Holtmann899e1072013-10-14 09:55:32 -07003689 if (window > interval)
3690 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3691 MGMT_STATUS_INVALID_PARAMS);
3692
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003693 hci_dev_lock(hdev);
3694
3695 hdev->le_scan_interval = interval;
3696 hdev->le_scan_window = window;
3697
3698 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3699
3700 hci_dev_unlock(hdev);
3701
3702 return err;
3703}
3704
Johan Hedberg33e38b32013-03-15 17:07:05 -05003705static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3706{
3707 struct pending_cmd *cmd;
3708
3709 BT_DBG("status 0x%02x", status);
3710
3711 hci_dev_lock(hdev);
3712
3713 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3714 if (!cmd)
3715 goto unlock;
3716
3717 if (status) {
3718 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3719 mgmt_status(status));
3720 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003721 struct mgmt_mode *cp = cmd->param;
3722
3723 if (cp->val)
3724 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3725 else
3726 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3727
Johan Hedberg33e38b32013-03-15 17:07:05 -05003728 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3729 new_settings(hdev, cmd->sk);
3730 }
3731
3732 mgmt_pending_remove(cmd);
3733
3734unlock:
3735 hci_dev_unlock(hdev);
3736}
3737
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003738static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003739 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003740{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003741 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003742 struct pending_cmd *cmd;
3743 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003744 int err;
3745
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003746 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003747
Johan Hedberg56f87902013-10-02 13:43:13 +03003748 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3749 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003750 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3751 MGMT_STATUS_NOT_SUPPORTED);
3752
Johan Hedberga7e80f22013-01-09 16:05:19 +02003753 if (cp->val != 0x00 && cp->val != 0x01)
3754 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3755 MGMT_STATUS_INVALID_PARAMS);
3756
Johan Hedberg5400c042012-02-21 16:40:33 +02003757 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003758 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003759 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003760
3761 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003762 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003763 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003764
3765 hci_dev_lock(hdev);
3766
Johan Hedberg05cbf292013-03-15 17:07:07 -05003767 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3768 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3769 MGMT_STATUS_BUSY);
3770 goto unlock;
3771 }
3772
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003773 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3774 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3775 hdev);
3776 goto unlock;
3777 }
3778
Johan Hedberg33e38b32013-03-15 17:07:05 -05003779 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3780 data, len);
3781 if (!cmd) {
3782 err = -ENOMEM;
3783 goto unlock;
3784 }
3785
3786 hci_req_init(&req, hdev);
3787
Johan Hedberg406d7802013-03-15 17:07:09 -05003788 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003789
3790 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003791 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003792 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003793 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003794 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003795 }
3796
Johan Hedberg33e38b32013-03-15 17:07:05 -05003797unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003798 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003799
Antti Julkuf6422ec2011-06-22 13:11:56 +03003800 return err;
3801}
3802
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003803static void set_bredr_scan(struct hci_request *req)
3804{
3805 struct hci_dev *hdev = req->hdev;
3806 u8 scan = 0;
3807
3808 /* Ensure that fast connectable is disabled. This function will
3809 * not do anything if the page scan parameters are already what
3810 * they should be.
3811 */
3812 write_fast_connectable(req, false);
3813
3814 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3815 scan |= SCAN_PAGE;
3816 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3817 scan |= SCAN_INQUIRY;
3818
3819 if (scan)
3820 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3821}
3822
Johan Hedberg0663ca22013-10-02 13:43:14 +03003823static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3824{
3825 struct pending_cmd *cmd;
3826
3827 BT_DBG("status 0x%02x", status);
3828
3829 hci_dev_lock(hdev);
3830
3831 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3832 if (!cmd)
3833 goto unlock;
3834
3835 if (status) {
3836 u8 mgmt_err = mgmt_status(status);
3837
3838 /* We need to restore the flag if related HCI commands
3839 * failed.
3840 */
3841 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3842
3843 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3844 } else {
3845 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3846 new_settings(hdev, cmd->sk);
3847 }
3848
3849 mgmt_pending_remove(cmd);
3850
3851unlock:
3852 hci_dev_unlock(hdev);
3853}
3854
3855static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3856{
3857 struct mgmt_mode *cp = data;
3858 struct pending_cmd *cmd;
3859 struct hci_request req;
3860 int err;
3861
3862 BT_DBG("request for %s", hdev->name);
3863
3864 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3865 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3866 MGMT_STATUS_NOT_SUPPORTED);
3867
3868 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3869 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3870 MGMT_STATUS_REJECTED);
3871
3872 if (cp->val != 0x00 && cp->val != 0x01)
3873 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3874 MGMT_STATUS_INVALID_PARAMS);
3875
3876 hci_dev_lock(hdev);
3877
3878 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3879 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3880 goto unlock;
3881 }
3882
3883 if (!hdev_is_powered(hdev)) {
3884 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003885 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3886 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3887 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3888 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3889 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3890 }
3891
3892 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3893
3894 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3895 if (err < 0)
3896 goto unlock;
3897
3898 err = new_settings(hdev, sk);
3899 goto unlock;
3900 }
3901
3902 /* Reject disabling when powered on */
3903 if (!cp->val) {
3904 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3905 MGMT_STATUS_REJECTED);
3906 goto unlock;
3907 }
3908
3909 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3910 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3911 MGMT_STATUS_BUSY);
3912 goto unlock;
3913 }
3914
3915 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3916 if (!cmd) {
3917 err = -ENOMEM;
3918 goto unlock;
3919 }
3920
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07003921 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03003922 * generates the correct flags.
3923 */
3924 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3925
3926 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003927
3928 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3929 set_bredr_scan(&req);
3930
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07003931 /* Since only the advertising data flags will change, there
3932 * is no need to update the scan response data.
3933 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07003934 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003935
Johan Hedberg0663ca22013-10-02 13:43:14 +03003936 err = hci_req_run(&req, set_bredr_complete);
3937 if (err < 0)
3938 mgmt_pending_remove(cmd);
3939
3940unlock:
3941 hci_dev_unlock(hdev);
3942 return err;
3943}
3944
Johan Hedberg3f706b72013-01-20 14:27:16 +02003945static bool ltk_is_valid(struct mgmt_ltk_info *key)
3946{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003947 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3948 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003949 if (key->master != 0x00 && key->master != 0x01)
3950 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003951 if (!bdaddr_type_is_le(key->addr.type))
3952 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003953 return true;
3954}
3955
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003956static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003957 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003958{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003959 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3960 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003961 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003962
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003963 BT_DBG("request for %s", hdev->name);
3964
3965 if (!lmp_le_capable(hdev))
3966 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3967 MGMT_STATUS_NOT_SUPPORTED);
3968
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003969 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003970
3971 expected_len = sizeof(*cp) + key_count *
3972 sizeof(struct mgmt_ltk_info);
3973 if (expected_len != len) {
3974 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003975 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003976 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003977 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003978 }
3979
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003980 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003981
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003982 for (i = 0; i < key_count; i++) {
3983 struct mgmt_ltk_info *key = &cp->keys[i];
3984
Johan Hedberg3f706b72013-01-20 14:27:16 +02003985 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003986 return cmd_status(sk, hdev->id,
3987 MGMT_OP_LOAD_LONG_TERM_KEYS,
3988 MGMT_STATUS_INVALID_PARAMS);
3989 }
3990
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003991 hci_dev_lock(hdev);
3992
3993 hci_smp_ltks_clear(hdev);
3994
3995 for (i = 0; i < key_count; i++) {
3996 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003997 u8 type, addr_type;
3998
3999 if (key->addr.type == BDADDR_LE_PUBLIC)
4000 addr_type = ADDR_LE_DEV_PUBLIC;
4001 else
4002 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004003
4004 if (key->master)
4005 type = HCI_SMP_LTK;
4006 else
4007 type = HCI_SMP_LTK_SLAVE;
4008
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004009 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004010 type, 0, key->authenticated, key->val,
4011 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004012 }
4013
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004014 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4015 NULL, 0);
4016
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004017 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004018
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004019 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004020}
4021
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004022static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004023 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4024 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004025 bool var_len;
4026 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004027} mgmt_handlers[] = {
4028 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004029 { read_version, false, MGMT_READ_VERSION_SIZE },
4030 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4031 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4032 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4033 { set_powered, false, MGMT_SETTING_SIZE },
4034 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4035 { set_connectable, false, MGMT_SETTING_SIZE },
4036 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4037 { set_pairable, false, MGMT_SETTING_SIZE },
4038 { set_link_security, false, MGMT_SETTING_SIZE },
4039 { set_ssp, false, MGMT_SETTING_SIZE },
4040 { set_hs, false, MGMT_SETTING_SIZE },
4041 { set_le, false, MGMT_SETTING_SIZE },
4042 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4043 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4044 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4045 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4046 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4047 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4048 { disconnect, false, MGMT_DISCONNECT_SIZE },
4049 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4050 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4051 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4052 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4053 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4054 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4055 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4056 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4057 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4058 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4059 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4060 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
4061 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
4062 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4063 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4064 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4065 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4066 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4067 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004068 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004069 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004070 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004071 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004072 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004073};
4074
4075
Johan Hedberg03811012010-12-08 00:21:06 +02004076int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4077{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004078 void *buf;
4079 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004080 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004081 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004082 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004083 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004084 int err;
4085
4086 BT_DBG("got %zu bytes", msglen);
4087
4088 if (msglen < sizeof(*hdr))
4089 return -EINVAL;
4090
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004091 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004092 if (!buf)
4093 return -ENOMEM;
4094
4095 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4096 err = -EFAULT;
4097 goto done;
4098 }
4099
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004100 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004101 opcode = __le16_to_cpu(hdr->opcode);
4102 index = __le16_to_cpu(hdr->index);
4103 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004104
4105 if (len != msglen - sizeof(*hdr)) {
4106 err = -EINVAL;
4107 goto done;
4108 }
4109
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004110 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004111 hdev = hci_dev_get(index);
4112 if (!hdev) {
4113 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004114 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004115 goto done;
4116 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004117
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004118 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4119 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004120 err = cmd_status(sk, index, opcode,
4121 MGMT_STATUS_INVALID_INDEX);
4122 goto done;
4123 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004124 }
4125
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004126 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004127 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004128 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004129 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004130 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004131 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004132 }
4133
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004134 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004135 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004136 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004137 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004138 goto done;
4139 }
4140
Johan Hedbergbe22b542012-03-01 22:24:41 +02004141 handler = &mgmt_handlers[opcode];
4142
4143 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004144 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004145 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004146 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004147 goto done;
4148 }
4149
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004150 if (hdev)
4151 mgmt_init_hdev(sk, hdev);
4152
4153 cp = buf + sizeof(*hdr);
4154
Johan Hedbergbe22b542012-03-01 22:24:41 +02004155 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004156 if (err < 0)
4157 goto done;
4158
Johan Hedberg03811012010-12-08 00:21:06 +02004159 err = msglen;
4160
4161done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004162 if (hdev)
4163 hci_dev_put(hdev);
4164
Johan Hedberg03811012010-12-08 00:21:06 +02004165 kfree(buf);
4166 return err;
4167}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004168
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004169void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004170{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004171 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004172 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004173
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004174 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004175}
4176
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004177void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004178{
Johan Hedberg5f159032012-03-02 03:13:19 +02004179 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004180
Marcel Holtmann1514b892013-10-06 08:25:01 -07004181 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004182 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004183
Johan Hedberg744cf192011-11-08 20:40:14 +02004184 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004185
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004186 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004187}
4188
Johan Hedberg229ab392013-03-15 17:06:53 -05004189static void powered_complete(struct hci_dev *hdev, u8 status)
4190{
4191 struct cmd_lookup match = { NULL, hdev };
4192
4193 BT_DBG("status 0x%02x", status);
4194
4195 hci_dev_lock(hdev);
4196
4197 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4198
4199 new_settings(hdev, match.sk);
4200
4201 hci_dev_unlock(hdev);
4202
4203 if (match.sk)
4204 sock_put(match.sk);
4205}
4206
Johan Hedberg70da6242013-03-15 17:06:51 -05004207static int powered_update_hci(struct hci_dev *hdev)
4208{
Johan Hedberg890ea892013-03-15 17:06:52 -05004209 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004210 u8 link_sec;
4211
Johan Hedberg890ea892013-03-15 17:06:52 -05004212 hci_req_init(&req, hdev);
4213
Johan Hedberg70da6242013-03-15 17:06:51 -05004214 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4215 !lmp_host_ssp_capable(hdev)) {
4216 u8 ssp = 1;
4217
Johan Hedberg890ea892013-03-15 17:06:52 -05004218 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004219 }
4220
Johan Hedbergc73eee92013-04-19 18:35:21 +03004221 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4222 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004223 struct hci_cp_write_le_host_supported cp;
4224
4225 cp.le = 1;
4226 cp.simul = lmp_le_br_capable(hdev);
4227
4228 /* Check first if we already have the right
4229 * host state (host features set)
4230 */
4231 if (cp.le != lmp_host_le_capable(hdev) ||
4232 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004233 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4234 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004235 }
4236
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004237 if (lmp_le_capable(hdev)) {
4238 /* Set random address to static address if configured */
4239 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4240 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4241 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004242
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004243 /* Make sure the controller has a good default for
4244 * advertising data. This also applies to the case
4245 * where BR/EDR was toggled during the AUTO_OFF phase.
4246 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004247 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004248 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004249 update_scan_rsp_data(&req);
4250 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004251
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004252 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4253 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004254 }
4255
Johan Hedberg70da6242013-03-15 17:06:51 -05004256 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4257 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004258 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4259 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004260
4261 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004262 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4263 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004264 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004265 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004266 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004267 }
4268
Johan Hedberg229ab392013-03-15 17:06:53 -05004269 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004270}
4271
Johan Hedberg744cf192011-11-08 20:40:14 +02004272int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004273{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004274 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004275 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4276 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004277 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004278
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004279 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4280 return 0;
4281
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004282 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004283 if (powered_update_hci(hdev) == 0)
4284 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004285
Johan Hedberg229ab392013-03-15 17:06:53 -05004286 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4287 &match);
4288 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004289 }
4290
Johan Hedberg229ab392013-03-15 17:06:53 -05004291 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4292 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4293
4294 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4295 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4296 zero_cod, sizeof(zero_cod), NULL);
4297
4298new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004299 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004300
4301 if (match.sk)
4302 sock_put(match.sk);
4303
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004304 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004305}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004306
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004307void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004308{
4309 struct pending_cmd *cmd;
4310 u8 status;
4311
4312 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4313 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004314 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004315
4316 if (err == -ERFKILL)
4317 status = MGMT_STATUS_RFKILLED;
4318 else
4319 status = MGMT_STATUS_FAILED;
4320
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004321 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004322
4323 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004324}
4325
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004326void mgmt_discoverable_timeout(struct hci_dev *hdev)
4327{
4328 struct hci_request req;
4329 u8 scan = SCAN_PAGE;
4330
4331 hci_dev_lock(hdev);
4332
4333 /* When discoverable timeout triggers, then just make sure
4334 * the limited discoverable flag is cleared. Even in the case
4335 * of a timeout triggered from general discoverable, it is
4336 * safe to unconditionally clear the flag.
4337 */
4338 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
4339
4340 hci_req_init(&req, hdev);
4341 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
4342 update_class(&req);
4343 hci_req_run(&req, NULL);
4344
4345 hdev->discov_timeout = 0;
4346
4347 hci_dev_unlock(hdev);
4348}
4349
Marcel Holtmann86a75642013-10-15 06:33:54 -07004350void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004351{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004352 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004353
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004354 /* Nothing needed here if there's a pending command since that
4355 * commands request completion callback takes care of everything
4356 * necessary.
4357 */
4358 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004359 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004360
Marcel Holtmann86a75642013-10-15 06:33:54 -07004361 if (discoverable)
4362 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4363 else
4364 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004365
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004366 if (changed)
Marcel Holtmann86a75642013-10-15 06:33:54 -07004367 new_settings(hdev, NULL);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004368}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004369
Marcel Holtmanna3309162013-10-15 06:33:55 -07004370void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004371{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004372 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004373
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004374 /* Nothing needed here if there's a pending command since that
4375 * commands request completion callback takes care of everything
4376 * necessary.
4377 */
4378 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004379 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004380
Marcel Holtmanna3309162013-10-15 06:33:55 -07004381 if (connectable)
4382 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4383 else
4384 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004385
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004386 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004387 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004388}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004389
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004390void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004391{
Johan Hedbergca69b792011-11-11 18:10:00 +02004392 u8 mgmt_err = mgmt_status(status);
4393
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004394 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004395 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004396 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004397
4398 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004399 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004400 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004401}
4402
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004403void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4404 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004405{
Johan Hedberg86742e12011-11-07 23:13:38 +02004406 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004407
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004408 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004409
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004410 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004411 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004412 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004413 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004414 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004415 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004416
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004417 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004418}
Johan Hedbergf7520542011-01-20 12:34:39 +02004419
Marcel Holtmann083368f2013-10-15 14:26:29 -07004420void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004421{
4422 struct mgmt_ev_new_long_term_key ev;
4423
4424 memset(&ev, 0, sizeof(ev));
4425
4426 ev.store_hint = persistent;
4427 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004428 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004429 ev.key.authenticated = key->authenticated;
4430 ev.key.enc_size = key->enc_size;
4431 ev.key.ediv = key->ediv;
4432
4433 if (key->type == HCI_SMP_LTK)
4434 ev.key.master = 1;
4435
4436 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4437 memcpy(ev.key.val, key->val, sizeof(key->val));
4438
Marcel Holtmann083368f2013-10-15 14:26:29 -07004439 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004440}
4441
Marcel Holtmann94933992013-10-15 10:26:39 -07004442static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4443 u8 data_len)
4444{
4445 eir[eir_len++] = sizeof(type) + data_len;
4446 eir[eir_len++] = type;
4447 memcpy(&eir[eir_len], data, data_len);
4448 eir_len += data_len;
4449
4450 return eir_len;
4451}
4452
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004453void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4454 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4455 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004456{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004457 char buf[512];
4458 struct mgmt_ev_device_connected *ev = (void *) buf;
4459 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004460
Johan Hedbergb644ba32012-01-17 21:48:47 +02004461 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004462 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004463
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004464 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004465
Johan Hedbergb644ba32012-01-17 21:48:47 +02004466 if (name_len > 0)
4467 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004468 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004469
4470 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004471 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004472 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004473
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004474 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004475
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004476 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4477 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004478}
4479
Johan Hedberg8962ee72011-01-20 12:40:27 +02004480static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4481{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004482 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004483 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004484 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004485
Johan Hedberg88c3df12012-02-09 14:27:38 +02004486 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4487 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004488
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004489 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004490 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004491
4492 *sk = cmd->sk;
4493 sock_hold(*sk);
4494
Johan Hedberga664b5b2011-02-19 12:06:02 -03004495 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004496}
4497
Johan Hedberg124f6e32012-02-09 13:50:12 +02004498static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004499{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004500 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004501 struct mgmt_cp_unpair_device *cp = cmd->param;
4502 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004503
4504 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004505 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4506 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004507
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004508 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4509
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004510 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004511
4512 mgmt_pending_remove(cmd);
4513}
4514
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004515void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4516 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004517{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004518 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004519 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004520
Johan Hedberg744cf192011-11-08 20:40:14 +02004521 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004522
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004523 bacpy(&ev.addr.bdaddr, bdaddr);
4524 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4525 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004526
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004527 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004528
4529 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004530 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004531
Johan Hedberg124f6e32012-02-09 13:50:12 +02004532 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004533 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004534}
4535
Marcel Holtmann78929242013-10-06 23:55:47 -07004536void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4537 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004538{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004539 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004540 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004541
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004542 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4543 hdev);
4544
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004545 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004546 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004547 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004548
Johan Hedberg88c3df12012-02-09 14:27:38 +02004549 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004550 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004551
Marcel Holtmann78929242013-10-06 23:55:47 -07004552 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4553 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004554
Johan Hedberga664b5b2011-02-19 12:06:02 -03004555 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004556}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004557
Marcel Holtmann445608d2013-10-06 23:55:48 -07004558void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4559 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004560{
4561 struct mgmt_ev_connect_failed ev;
4562
Johan Hedberg4c659c32011-11-07 23:13:39 +02004563 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004564 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004565 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004566
Marcel Holtmann445608d2013-10-06 23:55:48 -07004567 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004568}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004569
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004570void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004571{
4572 struct mgmt_ev_pin_code_request ev;
4573
Johan Hedbergd8457692012-02-17 14:24:57 +02004574 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004575 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004576 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004577
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004578 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004579}
4580
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004581void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4582 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004583{
4584 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004585 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004586
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004587 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004588 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004589 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004590
Johan Hedbergd8457692012-02-17 14:24:57 +02004591 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004592 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004593
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004594 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
4595 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004596
Johan Hedberga664b5b2011-02-19 12:06:02 -03004597 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004598}
4599
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004600void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4601 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004602{
4603 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004604 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004605
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004606 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004607 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004608 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004609
Johan Hedbergd8457692012-02-17 14:24:57 +02004610 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004611 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004612
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004613 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
4614 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004615
Johan Hedberga664b5b2011-02-19 12:06:02 -03004616 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004617}
Johan Hedberga5c29682011-02-19 12:05:57 -03004618
Johan Hedberg744cf192011-11-08 20:40:14 +02004619int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004620 u8 link_type, u8 addr_type, __le32 value,
4621 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004622{
4623 struct mgmt_ev_user_confirm_request ev;
4624
Johan Hedberg744cf192011-11-08 20:40:14 +02004625 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004626
Johan Hedberg272d90d2012-02-09 15:26:12 +02004627 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004628 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004629 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02004630 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004631
Johan Hedberg744cf192011-11-08 20:40:14 +02004632 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004633 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004634}
4635
Johan Hedberg272d90d2012-02-09 15:26:12 +02004636int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004637 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004638{
4639 struct mgmt_ev_user_passkey_request ev;
4640
4641 BT_DBG("%s", hdev->name);
4642
Johan Hedberg272d90d2012-02-09 15:26:12 +02004643 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004644 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004645
4646 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004647 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004648}
4649
Brian Gix0df4c182011-11-16 13:53:13 -08004650static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004651 u8 link_type, u8 addr_type, u8 status,
4652 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004653{
4654 struct pending_cmd *cmd;
4655 struct mgmt_rp_user_confirm_reply rp;
4656 int err;
4657
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004658 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004659 if (!cmd)
4660 return -ENOENT;
4661
Johan Hedberg272d90d2012-02-09 15:26:12 +02004662 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004663 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004664 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004665 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004666
Johan Hedberga664b5b2011-02-19 12:06:02 -03004667 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004668
4669 return err;
4670}
4671
Johan Hedberg744cf192011-11-08 20:40:14 +02004672int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004673 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004674{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004675 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004676 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004677}
4678
Johan Hedberg272d90d2012-02-09 15:26:12 +02004679int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004680 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004681{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004682 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004683 status,
4684 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004685}
Johan Hedberg2a611692011-02-19 12:06:00 -03004686
Brian Gix604086b2011-11-23 08:28:33 -08004687int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004688 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004689{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004690 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004691 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004692}
4693
Johan Hedberg272d90d2012-02-09 15:26:12 +02004694int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004695 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004696{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004697 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004698 status,
4699 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004700}
4701
Johan Hedberg92a25252012-09-06 18:39:26 +03004702int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4703 u8 link_type, u8 addr_type, u32 passkey,
4704 u8 entered)
4705{
4706 struct mgmt_ev_passkey_notify ev;
4707
4708 BT_DBG("%s", hdev->name);
4709
4710 bacpy(&ev.addr.bdaddr, bdaddr);
4711 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4712 ev.passkey = __cpu_to_le32(passkey);
4713 ev.entered = entered;
4714
4715 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4716}
4717
Marcel Holtmanne5460992013-10-15 14:26:23 -07004718void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4719 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004720{
4721 struct mgmt_ev_auth_failed ev;
4722
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004723 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004724 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004725 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004726
Marcel Holtmanne5460992013-10-15 14:26:23 -07004727 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004728}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004729
Marcel Holtmann464996a2013-10-15 14:26:24 -07004730void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004731{
4732 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07004733 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004734
4735 if (status) {
4736 u8 mgmt_err = mgmt_status(status);
4737 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004738 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07004739 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004740 }
4741
Marcel Holtmann464996a2013-10-15 14:26:24 -07004742 if (test_bit(HCI_AUTH, &hdev->flags))
4743 changed = !test_and_set_bit(HCI_LINK_SECURITY,
4744 &hdev->dev_flags);
4745 else
4746 changed = test_and_clear_bit(HCI_LINK_SECURITY,
4747 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02004748
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004749 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004750 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004751
Johan Hedberg47990ea2012-02-22 11:58:37 +02004752 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07004753 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004754
4755 if (match.sk)
4756 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004757}
4758
Johan Hedberg890ea892013-03-15 17:06:52 -05004759static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004760{
Johan Hedberg890ea892013-03-15 17:06:52 -05004761 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004762 struct hci_cp_write_eir cp;
4763
Johan Hedberg976eb202012-10-24 21:12:01 +03004764 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004765 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004766
Johan Hedbergc80da272012-02-22 15:38:48 +02004767 memset(hdev->eir, 0, sizeof(hdev->eir));
4768
Johan Hedbergcacaf522012-02-21 00:52:42 +02004769 memset(&cp, 0, sizeof(cp));
4770
Johan Hedberg890ea892013-03-15 17:06:52 -05004771 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004772}
4773
Marcel Holtmann3e248562013-10-15 14:26:25 -07004774void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004775{
4776 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004777 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004778 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004779
4780 if (status) {
4781 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004782
4783 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004784 &hdev->dev_flags)) {
4785 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004786 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004787 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004788
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004789 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4790 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004791 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004792 }
4793
4794 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004795 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004796 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004797 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4798 if (!changed)
4799 changed = test_and_clear_bit(HCI_HS_ENABLED,
4800 &hdev->dev_flags);
4801 else
4802 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004803 }
4804
4805 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4806
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004807 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07004808 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004809
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004810 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004811 sock_put(match.sk);
4812
Johan Hedberg890ea892013-03-15 17:06:52 -05004813 hci_req_init(&req, hdev);
4814
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004815 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004816 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004817 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004818 clear_eir(&req);
4819
4820 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004821}
4822
Johan Hedberg92da6092013-03-15 17:06:55 -05004823static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004824{
4825 struct cmd_lookup *match = data;
4826
Johan Hedberg90e70452012-02-23 23:09:40 +02004827 if (match->sk == NULL) {
4828 match->sk = cmd->sk;
4829 sock_hold(match->sk);
4830 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004831}
4832
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07004833void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
4834 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004835{
Johan Hedberg90e70452012-02-23 23:09:40 +02004836 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004837
Johan Hedberg92da6092013-03-15 17:06:55 -05004838 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4839 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4840 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004841
4842 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07004843 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
4844 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004845
4846 if (match.sk)
4847 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004848}
4849
Marcel Holtmann7667da32013-10-15 14:26:27 -07004850void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004851{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004852 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004853 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004854
Johan Hedberg13928972013-03-15 17:07:00 -05004855 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07004856 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004857
4858 memset(&ev, 0, sizeof(ev));
4859 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004860 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004861
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004862 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004863 if (!cmd) {
4864 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004865
Johan Hedberg13928972013-03-15 17:07:00 -05004866 /* If this is a HCI command related to powering on the
4867 * HCI dev don't send any mgmt signals.
4868 */
4869 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07004870 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004871 }
4872
Marcel Holtmann7667da32013-10-15 14:26:27 -07004873 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4874 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004875}
Szymon Jancc35938b2011-03-22 13:12:21 +01004876
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004877void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
4878 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004879{
4880 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01004881
Johan Hedberg744cf192011-11-08 20:40:14 +02004882 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004883
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004884 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004885 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004886 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01004887
4888 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004889 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4890 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004891 } else {
4892 struct mgmt_rp_read_local_oob_data rp;
4893
4894 memcpy(rp.hash, hash, sizeof(rp.hash));
4895 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4896
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004897 cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4898 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004899 }
4900
4901 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01004902}
Johan Hedberge17acd42011-03-30 23:57:16 +03004903
Marcel Holtmann901801b2013-10-06 23:55:51 -07004904void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4905 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4906 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004907{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004908 char buf[512];
4909 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004910 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004911
Andre Guedes12602d02013-04-30 15:29:40 -03004912 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004913 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004914
Johan Hedberg1dc06092012-01-15 21:01:23 +02004915 /* Leave 5 bytes for a potential CoD field */
4916 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004917 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004918
Johan Hedberg1dc06092012-01-15 21:01:23 +02004919 memset(buf, 0, sizeof(buf));
4920
Johan Hedberge319d2e2012-01-15 19:51:59 +02004921 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004922 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004923 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004924 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304925 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004926 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304927 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004928
Johan Hedberg1dc06092012-01-15 21:01:23 +02004929 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004930 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004931
Johan Hedberg1dc06092012-01-15 21:01:23 +02004932 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4933 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004934 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004935
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004936 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004937 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004938
Marcel Holtmann901801b2013-10-06 23:55:51 -07004939 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004940}
Johan Hedberga88a9652011-03-30 13:18:12 +03004941
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004942void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4943 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004944{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004945 struct mgmt_ev_device_found *ev;
4946 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4947 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004948
Johan Hedbergb644ba32012-01-17 21:48:47 +02004949 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004950
Johan Hedbergb644ba32012-01-17 21:48:47 +02004951 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004952
Johan Hedbergb644ba32012-01-17 21:48:47 +02004953 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004954 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004955 ev->rssi = rssi;
4956
4957 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004958 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004959
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004960 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004961
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004962 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004963}
Johan Hedberg314b2382011-04-27 10:29:57 -04004964
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004965void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004966{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004967 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004968 struct pending_cmd *cmd;
4969
Andre Guedes343fb142011-11-22 17:14:19 -03004970 BT_DBG("%s discovering %u", hdev->name, discovering);
4971
Johan Hedberg164a6e72011-11-01 17:06:44 +02004972 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004973 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004974 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004975 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004976
4977 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004978 u8 type = hdev->discovery.type;
4979
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004980 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4981 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004982 mgmt_pending_remove(cmd);
4983 }
4984
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004985 memset(&ev, 0, sizeof(ev));
4986 ev.type = hdev->discovery.type;
4987 ev.discovering = discovering;
4988
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004989 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004990}
Antti Julku5e762442011-08-25 16:48:02 +03004991
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004992int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004993{
4994 struct pending_cmd *cmd;
4995 struct mgmt_ev_device_blocked ev;
4996
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004997 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004998
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004999 bacpy(&ev.addr.bdaddr, bdaddr);
5000 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005001
Johan Hedberg744cf192011-11-08 20:40:14 +02005002 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005003 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005004}
5005
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005006int mgmt_device_unblocked(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_unblocked ev;
5010
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005011 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_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_UNBLOCKED, 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}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005019
5020static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5021{
5022 BT_DBG("%s status %u", hdev->name, status);
5023
5024 /* Clear the advertising mgmt setting if we failed to re-enable it */
5025 if (status) {
5026 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005027 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005028 }
5029}
5030
5031void mgmt_reenable_advertising(struct hci_dev *hdev)
5032{
5033 struct hci_request req;
5034
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005035 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005036 return;
5037
5038 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5039 return;
5040
5041 hci_req_init(&req, hdev);
5042 enable_advertising(&req);
5043
5044 /* If this fails we have no option but to let user space know
5045 * that we've disabled advertising.
5046 */
5047 if (hci_req_run(&req, adv_enable_complete) < 0) {
5048 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005049 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005050 }
5051}