blob: 285d571eee6b9c14f93194e87000107409e89b49 [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 Holtmann441ad2d2013-10-15 06:33:52 -0700539static u8 create_ad(struct hci_dev *hdev, u8 *ptr)
540{
541 u8 ad_len = 0, flags = 0;
542 size_t name_len;
543
544 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
545 flags |= LE_AD_GENERAL;
546
547 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
548 if (lmp_le_br_capable(hdev))
549 flags |= LE_AD_SIM_LE_BREDR_CTRL;
550 if (lmp_host_le_br_capable(hdev))
551 flags |= LE_AD_SIM_LE_BREDR_HOST;
552 } else {
553 flags |= LE_AD_NO_BREDR;
554 }
555
556 if (flags) {
557 BT_DBG("adv flags 0x%02x", flags);
558
559 ptr[0] = 2;
560 ptr[1] = EIR_FLAGS;
561 ptr[2] = flags;
562
563 ad_len += 3;
564 ptr += 3;
565 }
566
567 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
568 ptr[0] = 2;
569 ptr[1] = EIR_TX_POWER;
570 ptr[2] = (u8) hdev->adv_tx_power;
571
572 ad_len += 3;
573 ptr += 3;
574 }
575
576 name_len = strlen(hdev->dev_name);
577 if (name_len > 0) {
578 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
579
580 if (name_len > max_len) {
581 name_len = max_len;
582 ptr[1] = EIR_NAME_SHORT;
583 } else
584 ptr[1] = EIR_NAME_COMPLETE;
585
586 ptr[0] = name_len + 1;
587
588 memcpy(ptr + 2, hdev->dev_name, name_len);
589
590 ad_len += (name_len + 2);
591 ptr += (name_len + 2);
592 }
593
594 return ad_len;
595}
596
597static void update_ad(struct hci_request *req)
598{
599 struct hci_dev *hdev = req->hdev;
600 struct hci_cp_le_set_adv_data cp;
601 u8 len;
602
603 if (!lmp_le_capable(hdev))
604 return;
605
606 memset(&cp, 0, sizeof(cp));
607
608 len = create_ad(hdev, cp.data);
609
610 if (hdev->adv_data_len == len &&
611 memcmp(cp.data, hdev->adv_data, len) == 0)
612 return;
613
614 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
615 hdev->adv_data_len = len;
616
617 cp.length = len;
618
619 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
620}
621
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300622static void create_eir(struct hci_dev *hdev, u8 *data)
623{
624 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300625 size_t name_len;
626
627 name_len = strlen(hdev->dev_name);
628
629 if (name_len > 0) {
630 /* EIR Data type */
631 if (name_len > 48) {
632 name_len = 48;
633 ptr[1] = EIR_NAME_SHORT;
634 } else
635 ptr[1] = EIR_NAME_COMPLETE;
636
637 /* EIR Data length */
638 ptr[0] = name_len + 1;
639
640 memcpy(ptr + 2, hdev->dev_name, name_len);
641
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300642 ptr += (name_len + 2);
643 }
644
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100645 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700646 ptr[0] = 2;
647 ptr[1] = EIR_TX_POWER;
648 ptr[2] = (u8) hdev->inq_tx_power;
649
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700650 ptr += 3;
651 }
652
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700653 if (hdev->devid_source > 0) {
654 ptr[0] = 9;
655 ptr[1] = EIR_DEVICE_ID;
656
657 put_unaligned_le16(hdev->devid_source, ptr + 2);
658 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
659 put_unaligned_le16(hdev->devid_product, ptr + 6);
660 put_unaligned_le16(hdev->devid_version, ptr + 8);
661
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700662 ptr += 10;
663 }
664
Johan Hedberg213202e2013-01-27 00:31:33 +0200665 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200666 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200667 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300668}
669
Johan Hedberg890ea892013-03-15 17:06:52 -0500670static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300671{
Johan Hedberg890ea892013-03-15 17:06:52 -0500672 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300673 struct hci_cp_write_eir cp;
674
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200675 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500676 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200677
Johan Hedberg976eb202012-10-24 21:12:01 +0300678 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500679 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300680
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200681 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500682 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300683
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200684 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500685 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300686
687 memset(&cp, 0, sizeof(cp));
688
689 create_eir(hdev, cp.data);
690
691 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500692 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300693
694 memcpy(hdev->eir, cp.data, sizeof(cp.data));
695
Johan Hedberg890ea892013-03-15 17:06:52 -0500696 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300697}
698
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200699static u8 get_service_classes(struct hci_dev *hdev)
700{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300701 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200702 u8 val = 0;
703
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300704 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200705 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200706
707 return val;
708}
709
Johan Hedberg890ea892013-03-15 17:06:52 -0500710static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200711{
Johan Hedberg890ea892013-03-15 17:06:52 -0500712 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200713 u8 cod[3];
714
715 BT_DBG("%s", hdev->name);
716
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200717 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500718 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200719
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200720 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500721 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200722
723 cod[0] = hdev->minor_class;
724 cod[1] = hdev->major_class;
725 cod[2] = get_service_classes(hdev);
726
727 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500728 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200729
Johan Hedberg890ea892013-03-15 17:06:52 -0500730 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200731}
732
Johan Hedberg7d785252011-12-15 00:47:39 +0200733static void service_cache_off(struct work_struct *work)
734{
735 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300736 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500737 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200738
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200739 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200740 return;
741
Johan Hedberg890ea892013-03-15 17:06:52 -0500742 hci_req_init(&req, hdev);
743
Johan Hedberg7d785252011-12-15 00:47:39 +0200744 hci_dev_lock(hdev);
745
Johan Hedberg890ea892013-03-15 17:06:52 -0500746 update_eir(&req);
747 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200748
749 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500750
751 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200752}
753
Johan Hedberg6a919082012-02-28 06:17:26 +0200754static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200755{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200756 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200757 return;
758
Johan Hedberg4f87da82012-03-02 19:55:56 +0200759 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200760
Johan Hedberg4f87da82012-03-02 19:55:56 +0200761 /* Non-mgmt controlled devices get this bit set
762 * implicitly so that pairing works for them, however
763 * for mgmt we require user-space to explicitly enable
764 * it
765 */
766 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200767}
768
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200769static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300770 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200771{
772 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200773
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200774 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200775
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300776 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200777
Johan Hedberg03811012010-12-08 00:21:06 +0200778 memset(&rp, 0, sizeof(rp));
779
Johan Hedberg03811012010-12-08 00:21:06 +0200780 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200781
782 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200783 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200784
785 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
786 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
787
788 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200789
790 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200791 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200792
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300793 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200794
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200795 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300796 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200797}
798
799static void mgmt_pending_free(struct pending_cmd *cmd)
800{
801 sock_put(cmd->sk);
802 kfree(cmd->param);
803 kfree(cmd);
804}
805
806static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300807 struct hci_dev *hdev, void *data,
808 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200809{
810 struct pending_cmd *cmd;
811
Andre Guedes12b94562012-06-07 19:05:45 -0300812 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200813 if (!cmd)
814 return NULL;
815
816 cmd->opcode = opcode;
817 cmd->index = hdev->id;
818
Andre Guedes12b94562012-06-07 19:05:45 -0300819 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200820 if (!cmd->param) {
821 kfree(cmd);
822 return NULL;
823 }
824
825 if (data)
826 memcpy(cmd->param, data, len);
827
828 cmd->sk = sk;
829 sock_hold(sk);
830
831 list_add(&cmd->list, &hdev->mgmt_pending);
832
833 return cmd;
834}
835
836static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300837 void (*cb)(struct pending_cmd *cmd,
838 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300839 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200840{
Andre Guedesa3d09352013-02-01 11:21:30 -0300841 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200842
Andre Guedesa3d09352013-02-01 11:21:30 -0300843 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200844 if (opcode > 0 && cmd->opcode != opcode)
845 continue;
846
847 cb(cmd, data);
848 }
849}
850
851static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
852{
853 struct pending_cmd *cmd;
854
855 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
856 if (cmd->opcode == opcode)
857 return cmd;
858 }
859
860 return NULL;
861}
862
863static void mgmt_pending_remove(struct pending_cmd *cmd)
864{
865 list_del(&cmd->list);
866 mgmt_pending_free(cmd);
867}
868
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200869static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200870{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200871 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200872
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200873 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300874 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200875}
876
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200877static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300878 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200879{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300880 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200881 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200882 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200883
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200884 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200885
Johan Hedberga7e80f22013-01-09 16:05:19 +0200886 if (cp->val != 0x00 && cp->val != 0x01)
887 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
888 MGMT_STATUS_INVALID_PARAMS);
889
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300890 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200891
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300892 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
893 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
894 MGMT_STATUS_BUSY);
895 goto failed;
896 }
897
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100898 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
899 cancel_delayed_work(&hdev->power_off);
900
901 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200902 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
903 data, len);
904 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100905 goto failed;
906 }
907 }
908
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200909 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200910 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200911 goto failed;
912 }
913
Johan Hedberg03811012010-12-08 00:21:06 +0200914 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
915 if (!cmd) {
916 err = -ENOMEM;
917 goto failed;
918 }
919
920 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200921 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200922 else
Johan Hedberg19202572013-01-14 22:33:51 +0200923 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200924
925 err = 0;
926
927failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300928 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200929 return err;
930}
931
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300932static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
933 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200934{
935 struct sk_buff *skb;
936 struct mgmt_hdr *hdr;
937
Andre Guedes790eff42012-06-07 19:05:46 -0300938 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200939 if (!skb)
940 return -ENOMEM;
941
942 hdr = (void *) skb_put(skb, sizeof(*hdr));
943 hdr->opcode = cpu_to_le16(event);
944 if (hdev)
945 hdr->index = cpu_to_le16(hdev->id);
946 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530947 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200948 hdr->len = cpu_to_le16(data_len);
949
950 if (data)
951 memcpy(skb_put(skb, data_len), data, data_len);
952
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100953 /* Time stamp */
954 __net_timestamp(skb);
955
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200956 hci_send_to_control(skb, skip_sk);
957 kfree_skb(skb);
958
959 return 0;
960}
961
962static int new_settings(struct hci_dev *hdev, struct sock *skip)
963{
964 __le32 ev;
965
966 ev = cpu_to_le32(get_current_settings(hdev));
967
968 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
969}
970
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300971struct cmd_lookup {
972 struct sock *sk;
973 struct hci_dev *hdev;
974 u8 mgmt_status;
975};
976
977static void settings_rsp(struct pending_cmd *cmd, void *data)
978{
979 struct cmd_lookup *match = data;
980
981 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
982
983 list_del(&cmd->list);
984
985 if (match->sk == NULL) {
986 match->sk = cmd->sk;
987 sock_hold(match->sk);
988 }
989
990 mgmt_pending_free(cmd);
991}
992
993static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
994{
995 u8 *status = data;
996
997 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
998 mgmt_pending_remove(cmd);
999}
1000
Johan Hedberge6fe7982013-10-02 15:45:22 +03001001static u8 mgmt_bredr_support(struct hci_dev *hdev)
1002{
1003 if (!lmp_bredr_capable(hdev))
1004 return MGMT_STATUS_NOT_SUPPORTED;
1005 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1006 return MGMT_STATUS_REJECTED;
1007 else
1008 return MGMT_STATUS_SUCCESS;
1009}
1010
1011static u8 mgmt_le_support(struct hci_dev *hdev)
1012{
1013 if (!lmp_le_capable(hdev))
1014 return MGMT_STATUS_NOT_SUPPORTED;
1015 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1016 return MGMT_STATUS_REJECTED;
1017 else
1018 return MGMT_STATUS_SUCCESS;
1019}
1020
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001021static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1022{
1023 struct pending_cmd *cmd;
1024 struct mgmt_mode *cp;
1025 bool changed;
1026
1027 BT_DBG("status 0x%02x", status);
1028
1029 hci_dev_lock(hdev);
1030
1031 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1032 if (!cmd)
1033 goto unlock;
1034
1035 if (status) {
1036 u8 mgmt_err = mgmt_status(status);
1037 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1038 goto remove_cmd;
1039 }
1040
1041 cp = cmd->param;
1042 if (cp->val)
1043 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1044 &hdev->dev_flags);
1045 else
1046 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1047 &hdev->dev_flags);
1048
1049 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1050
1051 if (changed)
1052 new_settings(hdev, cmd->sk);
1053
1054remove_cmd:
1055 mgmt_pending_remove(cmd);
1056
1057unlock:
1058 hci_dev_unlock(hdev);
1059}
1060
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001061static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001062 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001063{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001064 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001065 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001066 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001067 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001068 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001069 int err;
1070
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001071 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001072
Johan Hedberge6fe7982013-10-02 15:45:22 +03001073 status = mgmt_bredr_support(hdev);
1074 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001075 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001076 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001077
Johan Hedberga7e80f22013-01-09 16:05:19 +02001078 if (cp->val != 0x00 && cp->val != 0x01)
1079 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1080 MGMT_STATUS_INVALID_PARAMS);
1081
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001082 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +01001083 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001084 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001085 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001086
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001087 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001088
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001089 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001090 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001091 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001092 goto failed;
1093 }
1094
1095 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001096 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001097 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001098 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001099 goto failed;
1100 }
1101
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001102 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001103 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001104 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001105 goto failed;
1106 }
1107
1108 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001109 bool changed = false;
1110
1111 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1112 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1113 changed = true;
1114 }
1115
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001116 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001117 if (err < 0)
1118 goto failed;
1119
1120 if (changed)
1121 err = new_settings(hdev, sk);
1122
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001123 goto failed;
1124 }
1125
1126 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +01001127 if (hdev->discov_timeout > 0) {
1128 cancel_delayed_work(&hdev->discov_off);
1129 hdev->discov_timeout = 0;
1130 }
1131
1132 if (cp->val && timeout > 0) {
1133 hdev->discov_timeout = timeout;
1134 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1135 msecs_to_jiffies(hdev->discov_timeout * 1000));
1136 }
1137
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001138 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001139 goto failed;
1140 }
1141
1142 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1143 if (!cmd) {
1144 err = -ENOMEM;
1145 goto failed;
1146 }
1147
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001148 hci_req_init(&req, hdev);
1149
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001150 scan = SCAN_PAGE;
1151
1152 if (cp->val)
1153 scan |= SCAN_INQUIRY;
1154 else
1155 cancel_delayed_work(&hdev->discov_off);
1156
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001157 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1158
1159 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001160 if (err < 0)
1161 mgmt_pending_remove(cmd);
1162
1163 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001164 hdev->discov_timeout = timeout;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001165
1166failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001167 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001168 return err;
1169}
1170
Johan Hedberg406d7802013-03-15 17:07:09 -05001171static void write_fast_connectable(struct hci_request *req, bool enable)
1172{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001173 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001174 struct hci_cp_write_page_scan_activity acp;
1175 u8 type;
1176
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001177 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1178 return;
1179
Johan Hedberg406d7802013-03-15 17:07:09 -05001180 if (enable) {
1181 type = PAGE_SCAN_TYPE_INTERLACED;
1182
1183 /* 160 msec page scan interval */
1184 acp.interval = __constant_cpu_to_le16(0x0100);
1185 } else {
1186 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1187
1188 /* default 1.28 sec page scan */
1189 acp.interval = __constant_cpu_to_le16(0x0800);
1190 }
1191
1192 acp.window = __constant_cpu_to_le16(0x0012);
1193
Johan Hedbergbd98b992013-03-15 17:07:13 -05001194 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1195 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1196 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1197 sizeof(acp), &acp);
1198
1199 if (hdev->page_scan_type != type)
1200 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001201}
1202
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001203static u8 get_adv_type(struct hci_dev *hdev)
1204{
1205 struct pending_cmd *cmd;
1206 bool connectable;
1207
1208 /* If there's a pending mgmt command the flag will not yet have
1209 * it's final value, so check for this first.
1210 */
1211 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1212 if (cmd) {
1213 struct mgmt_mode *cp = cmd->param;
1214 connectable = !!cp->val;
1215 } else {
1216 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1217 }
1218
1219 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1220}
1221
Johan Hedberg95c66e72013-10-14 16:20:06 +03001222static void enable_advertising(struct hci_request *req)
1223{
1224 struct hci_dev *hdev = req->hdev;
1225 struct hci_cp_le_set_adv_param cp;
1226 u8 enable = 0x01;
1227
1228 memset(&cp, 0, sizeof(cp));
1229 cp.min_interval = __constant_cpu_to_le16(0x0800);
1230 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001231 cp.type = get_adv_type(hdev);
Johan Hedberg95c66e72013-10-14 16:20:06 +03001232 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1233 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1234 else
1235 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1236 cp.channel_map = 0x07;
1237
1238 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1239
1240 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1241}
1242
1243static void disable_advertising(struct hci_request *req)
1244{
1245 u8 enable = 0x00;
1246
1247 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1248}
1249
Johan Hedberg2b76f452013-03-15 17:07:04 -05001250static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1251{
1252 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001253 struct mgmt_mode *cp;
1254 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001255
1256 BT_DBG("status 0x%02x", status);
1257
1258 hci_dev_lock(hdev);
1259
1260 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1261 if (!cmd)
1262 goto unlock;
1263
Johan Hedberg37438c12013-10-14 16:20:05 +03001264 if (status) {
1265 u8 mgmt_err = mgmt_status(status);
1266 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1267 goto remove_cmd;
1268 }
1269
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001270 cp = cmd->param;
1271 if (cp->val)
1272 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1273 else
1274 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1275
Johan Hedberg2b76f452013-03-15 17:07:04 -05001276 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1277
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001278 if (changed)
1279 new_settings(hdev, cmd->sk);
1280
Johan Hedberg37438c12013-10-14 16:20:05 +03001281remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001282 mgmt_pending_remove(cmd);
1283
1284unlock:
1285 hci_dev_unlock(hdev);
1286}
1287
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001288static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001289 u16 len)
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001290{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001291 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001292 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001293 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001294 u8 scan;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001295 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001296
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001297 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001298
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001299 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1300 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001301 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001302 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001303
Johan Hedberga7e80f22013-01-09 16:05:19 +02001304 if (cp->val != 0x00 && cp->val != 0x01)
1305 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1306 MGMT_STATUS_INVALID_PARAMS);
1307
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001308 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001309
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001310 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001311 bool changed = false;
1312
1313 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1314 changed = true;
1315
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001316 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001317 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001318 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001319 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1320 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1321 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001322
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001323 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001324 if (err < 0)
1325 goto failed;
1326
1327 if (changed)
1328 err = new_settings(hdev, sk);
1329
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001330 goto failed;
1331 }
1332
1333 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001334 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001335 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001336 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001337 goto failed;
1338 }
1339
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001340 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1341 if (!cmd) {
1342 err = -ENOMEM;
1343 goto failed;
1344 }
1345
Johan Hedberg2b76f452013-03-15 17:07:04 -05001346 hci_req_init(&req, hdev);
1347
Johan Hedberg9b742462013-10-14 16:20:03 +03001348 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) &&
1349 cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001350 if (cp->val) {
1351 scan = SCAN_PAGE;
1352 } else {
1353 scan = 0;
1354
1355 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001356 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001357 cancel_delayed_work(&hdev->discov_off);
1358 }
1359
1360 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1361 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001362
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001363 /* If we're going from non-connectable to connectable or
1364 * vice-versa when fast connectable is enabled ensure that fast
1365 * connectable gets disabled. write_fast_connectable won't do
1366 * anything if the page scan parameters are already what they
1367 * should be.
1368 */
1369 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001370 write_fast_connectable(&req, false);
1371
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001372 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1373 hci_conn_num(hdev, LE_LINK) == 0) {
1374 disable_advertising(&req);
1375 enable_advertising(&req);
1376 }
1377
Johan Hedberg2b76f452013-03-15 17:07:04 -05001378 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001379 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001380 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001381 if (err == -ENODATA)
1382 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE,
1383 hdev);
1384 goto failed;
1385 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001386
1387failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001388 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001389 return err;
1390}
1391
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001392static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001393 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001394{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001395 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001396 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001397 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001398
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001399 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001400
Johan Hedberga7e80f22013-01-09 16:05:19 +02001401 if (cp->val != 0x00 && cp->val != 0x01)
1402 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1403 MGMT_STATUS_INVALID_PARAMS);
1404
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001405 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001406
1407 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001408 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001409 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001410 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001411
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001412 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001413 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001414 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001415
Marcel Holtmann55594352013-10-06 16:11:57 -07001416 if (changed)
1417 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001418
Marcel Holtmann55594352013-10-06 16:11:57 -07001419unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001420 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001421 return err;
1422}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001423
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001424static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1425 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001426{
1427 struct mgmt_mode *cp = data;
1428 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001429 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001430 int err;
1431
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001432 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001433
Johan Hedberge6fe7982013-10-02 15:45:22 +03001434 status = mgmt_bredr_support(hdev);
1435 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001436 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001437 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001438
Johan Hedberga7e80f22013-01-09 16:05:19 +02001439 if (cp->val != 0x00 && cp->val != 0x01)
1440 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1441 MGMT_STATUS_INVALID_PARAMS);
1442
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001443 hci_dev_lock(hdev);
1444
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001445 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001446 bool changed = false;
1447
1448 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001449 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001450 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1451 changed = true;
1452 }
1453
1454 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1455 if (err < 0)
1456 goto failed;
1457
1458 if (changed)
1459 err = new_settings(hdev, sk);
1460
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001461 goto failed;
1462 }
1463
1464 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001465 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001466 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001467 goto failed;
1468 }
1469
1470 val = !!cp->val;
1471
1472 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1473 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1474 goto failed;
1475 }
1476
1477 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1478 if (!cmd) {
1479 err = -ENOMEM;
1480 goto failed;
1481 }
1482
1483 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1484 if (err < 0) {
1485 mgmt_pending_remove(cmd);
1486 goto failed;
1487 }
1488
1489failed:
1490 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001491 return err;
1492}
1493
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001494static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001495{
1496 struct mgmt_mode *cp = data;
1497 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001498 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001499 int err;
1500
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001501 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001502
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001503 status = mgmt_bredr_support(hdev);
1504 if (status)
1505 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1506
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001507 if (!lmp_ssp_capable(hdev))
1508 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1509 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001510
Johan Hedberga7e80f22013-01-09 16:05:19 +02001511 if (cp->val != 0x00 && cp->val != 0x01)
1512 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1513 MGMT_STATUS_INVALID_PARAMS);
1514
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001515 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001516
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001517 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001518 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001519
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001520 if (cp->val) {
1521 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1522 &hdev->dev_flags);
1523 } else {
1524 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1525 &hdev->dev_flags);
1526 if (!changed)
1527 changed = test_and_clear_bit(HCI_HS_ENABLED,
1528 &hdev->dev_flags);
1529 else
1530 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001531 }
1532
1533 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1534 if (err < 0)
1535 goto failed;
1536
1537 if (changed)
1538 err = new_settings(hdev, sk);
1539
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001540 goto failed;
1541 }
1542
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001543 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1544 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001545 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1546 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001547 goto failed;
1548 }
1549
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001550 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001551 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1552 goto failed;
1553 }
1554
1555 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1556 if (!cmd) {
1557 err = -ENOMEM;
1558 goto failed;
1559 }
1560
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001561 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001562 if (err < 0) {
1563 mgmt_pending_remove(cmd);
1564 goto failed;
1565 }
1566
1567failed:
1568 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001569 return err;
1570}
1571
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001572static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001573{
1574 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001575 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001576 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001577 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001578
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001579 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001580
Johan Hedberge6fe7982013-10-02 15:45:22 +03001581 status = mgmt_bredr_support(hdev);
1582 if (status)
1583 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001584
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001585 if (!lmp_ssp_capable(hdev))
1586 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1587 MGMT_STATUS_NOT_SUPPORTED);
1588
1589 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1590 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1591 MGMT_STATUS_REJECTED);
1592
Johan Hedberga7e80f22013-01-09 16:05:19 +02001593 if (cp->val != 0x00 && cp->val != 0x01)
1594 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1595 MGMT_STATUS_INVALID_PARAMS);
1596
Marcel Holtmannee392692013-10-01 22:59:23 -07001597 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001598
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001599 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001600 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001601 } else {
1602 if (hdev_is_powered(hdev)) {
1603 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1604 MGMT_STATUS_REJECTED);
1605 goto unlock;
1606 }
1607
Marcel Holtmannee392692013-10-01 22:59:23 -07001608 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001609 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001610
1611 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1612 if (err < 0)
1613 goto unlock;
1614
1615 if (changed)
1616 err = new_settings(hdev, sk);
1617
1618unlock:
1619 hci_dev_unlock(hdev);
1620 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001621}
1622
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001623static void le_enable_complete(struct hci_dev *hdev, u8 status)
1624{
1625 struct cmd_lookup match = { NULL, hdev };
1626
1627 if (status) {
1628 u8 mgmt_err = mgmt_status(status);
1629
1630 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1631 &mgmt_err);
1632 return;
1633 }
1634
1635 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1636
1637 new_settings(hdev, match.sk);
1638
1639 if (match.sk)
1640 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001641
1642 /* Make sure the controller has a good default for
1643 * advertising data. Restrict the update to when LE
1644 * has actually been enabled. During power on, the
1645 * update in powered_update_hci will take care of it.
1646 */
1647 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1648 struct hci_request req;
1649
1650 hci_dev_lock(hdev);
1651
1652 hci_req_init(&req, hdev);
1653 update_ad(&req);
1654 hci_req_run(&req, NULL);
1655
1656 hci_dev_unlock(hdev);
1657 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001658}
1659
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001660static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001661{
1662 struct mgmt_mode *cp = data;
1663 struct hci_cp_write_le_host_supported hci_cp;
1664 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001665 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001666 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001667 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001668
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001669 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001670
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001671 if (!lmp_le_capable(hdev))
1672 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1673 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001674
Johan Hedberga7e80f22013-01-09 16:05:19 +02001675 if (cp->val != 0x00 && cp->val != 0x01)
1676 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1677 MGMT_STATUS_INVALID_PARAMS);
1678
Johan Hedbergc73eee92013-04-19 18:35:21 +03001679 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001680 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001681 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1682 MGMT_STATUS_REJECTED);
1683
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001684 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001685
1686 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001687 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001688
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001689 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001690 bool changed = false;
1691
1692 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1693 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1694 changed = true;
1695 }
1696
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001697 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1698 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001699 changed = true;
1700 }
1701
Johan Hedberg06199cf2012-02-22 16:37:11 +02001702 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1703 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001704 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001705
1706 if (changed)
1707 err = new_settings(hdev, sk);
1708
Johan Hedberg1de028c2012-02-29 19:55:35 -08001709 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001710 }
1711
Johan Hedberg4375f102013-09-25 13:26:10 +03001712 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1713 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001714 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001715 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001716 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001717 }
1718
1719 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1720 if (!cmd) {
1721 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001722 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001723 }
1724
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001725 hci_req_init(&req, hdev);
1726
Johan Hedberg06199cf2012-02-22 16:37:11 +02001727 memset(&hci_cp, 0, sizeof(hci_cp));
1728
1729 if (val) {
1730 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001731 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001732 } else {
1733 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1734 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001735 }
1736
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001737 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1738 &hci_cp);
1739
1740 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301741 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001742 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001743
Johan Hedberg1de028c2012-02-29 19:55:35 -08001744unlock:
1745 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001746 return err;
1747}
1748
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001749/* This is a helper function to test for pending mgmt commands that can
1750 * cause CoD or EIR HCI commands. We can only allow one such pending
1751 * mgmt command at a time since otherwise we cannot easily track what
1752 * the current values are, will be, and based on that calculate if a new
1753 * HCI command needs to be sent and if yes with what value.
1754 */
1755static bool pending_eir_or_class(struct hci_dev *hdev)
1756{
1757 struct pending_cmd *cmd;
1758
1759 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1760 switch (cmd->opcode) {
1761 case MGMT_OP_ADD_UUID:
1762 case MGMT_OP_REMOVE_UUID:
1763 case MGMT_OP_SET_DEV_CLASS:
1764 case MGMT_OP_SET_POWERED:
1765 return true;
1766 }
1767 }
1768
1769 return false;
1770}
1771
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001772static const u8 bluetooth_base_uuid[] = {
1773 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1774 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1775};
1776
1777static u8 get_uuid_size(const u8 *uuid)
1778{
1779 u32 val;
1780
1781 if (memcmp(uuid, bluetooth_base_uuid, 12))
1782 return 128;
1783
1784 val = get_unaligned_le32(&uuid[12]);
1785 if (val > 0xffff)
1786 return 32;
1787
1788 return 16;
1789}
1790
Johan Hedberg92da6092013-03-15 17:06:55 -05001791static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1792{
1793 struct pending_cmd *cmd;
1794
1795 hci_dev_lock(hdev);
1796
1797 cmd = mgmt_pending_find(mgmt_op, hdev);
1798 if (!cmd)
1799 goto unlock;
1800
1801 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1802 hdev->dev_class, 3);
1803
1804 mgmt_pending_remove(cmd);
1805
1806unlock:
1807 hci_dev_unlock(hdev);
1808}
1809
1810static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1811{
1812 BT_DBG("status 0x%02x", status);
1813
1814 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1815}
1816
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001817static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001818{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001819 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001820 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001821 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001822 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001823 int err;
1824
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001825 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001826
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001827 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001828
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001829 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001830 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001831 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001832 goto failed;
1833 }
1834
Andre Guedes92c4c202012-06-07 19:05:44 -03001835 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001836 if (!uuid) {
1837 err = -ENOMEM;
1838 goto failed;
1839 }
1840
1841 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001842 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001843 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001844
Johan Hedbergde66aa62013-01-27 00:31:27 +02001845 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001846
Johan Hedberg890ea892013-03-15 17:06:52 -05001847 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001848
Johan Hedberg890ea892013-03-15 17:06:52 -05001849 update_class(&req);
1850 update_eir(&req);
1851
Johan Hedberg92da6092013-03-15 17:06:55 -05001852 err = hci_req_run(&req, add_uuid_complete);
1853 if (err < 0) {
1854 if (err != -ENODATA)
1855 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001856
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001857 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001858 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001859 goto failed;
1860 }
1861
1862 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001863 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001864 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001865 goto failed;
1866 }
1867
1868 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001869
1870failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001871 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001872 return err;
1873}
1874
Johan Hedberg24b78d02012-02-23 23:24:30 +02001875static bool enable_service_cache(struct hci_dev *hdev)
1876{
1877 if (!hdev_is_powered(hdev))
1878 return false;
1879
1880 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001881 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1882 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001883 return true;
1884 }
1885
1886 return false;
1887}
1888
Johan Hedberg92da6092013-03-15 17:06:55 -05001889static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1890{
1891 BT_DBG("status 0x%02x", status);
1892
1893 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1894}
1895
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001896static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001897 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001898{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001899 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001900 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001901 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001902 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 -05001903 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001904 int err, found;
1905
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001906 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001907
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001908 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001909
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001910 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001911 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001912 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001913 goto unlock;
1914 }
1915
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001916 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1917 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001918
Johan Hedberg24b78d02012-02-23 23:24:30 +02001919 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001920 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001921 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001922 goto unlock;
1923 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001924
Johan Hedberg9246a862012-02-23 21:33:16 +02001925 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001926 }
1927
1928 found = 0;
1929
Johan Hedberg056341c2013-01-27 00:31:30 +02001930 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001931 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1932 continue;
1933
1934 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001935 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001936 found++;
1937 }
1938
1939 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001940 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001941 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001942 goto unlock;
1943 }
1944
Johan Hedberg9246a862012-02-23 21:33:16 +02001945update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001946 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001947
Johan Hedberg890ea892013-03-15 17:06:52 -05001948 update_class(&req);
1949 update_eir(&req);
1950
Johan Hedberg92da6092013-03-15 17:06:55 -05001951 err = hci_req_run(&req, remove_uuid_complete);
1952 if (err < 0) {
1953 if (err != -ENODATA)
1954 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001955
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001956 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001957 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001958 goto unlock;
1959 }
1960
1961 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001962 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001963 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001964 goto unlock;
1965 }
1966
1967 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001968
1969unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001970 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001971 return err;
1972}
1973
Johan Hedberg92da6092013-03-15 17:06:55 -05001974static void set_class_complete(struct hci_dev *hdev, u8 status)
1975{
1976 BT_DBG("status 0x%02x", status);
1977
1978 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1979}
1980
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001981static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001982 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001983{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001984 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001985 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001986 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001987 int err;
1988
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001989 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001990
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001991 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001992 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1993 MGMT_STATUS_NOT_SUPPORTED);
1994
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001995 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001996
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001997 if (pending_eir_or_class(hdev)) {
1998 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1999 MGMT_STATUS_BUSY);
2000 goto unlock;
2001 }
2002
2003 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2004 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2005 MGMT_STATUS_INVALID_PARAMS);
2006 goto unlock;
2007 }
2008
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002009 hdev->major_class = cp->major;
2010 hdev->minor_class = cp->minor;
2011
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002012 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002013 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002014 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002015 goto unlock;
2016 }
2017
Johan Hedberg890ea892013-03-15 17:06:52 -05002018 hci_req_init(&req, hdev);
2019
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002020 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002021 hci_dev_unlock(hdev);
2022 cancel_delayed_work_sync(&hdev->service_cache);
2023 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002024 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002025 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002026
Johan Hedberg890ea892013-03-15 17:06:52 -05002027 update_class(&req);
2028
Johan Hedberg92da6092013-03-15 17:06:55 -05002029 err = hci_req_run(&req, set_class_complete);
2030 if (err < 0) {
2031 if (err != -ENODATA)
2032 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002033
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002034 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002035 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002036 goto unlock;
2037 }
2038
2039 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002040 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002041 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002042 goto unlock;
2043 }
2044
2045 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002046
Johan Hedbergb5235a62012-02-21 14:32:24 +02002047unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002048 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002049 return err;
2050}
2051
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002052static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002053 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002054{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002055 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002056 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002057 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002058
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002059 BT_DBG("request for %s", hdev->name);
2060
2061 if (!lmp_bredr_capable(hdev))
2062 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2063 MGMT_STATUS_NOT_SUPPORTED);
2064
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002065 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002066
Johan Hedberg86742e12011-11-07 23:13:38 +02002067 expected_len = sizeof(*cp) + key_count *
2068 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002069 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002070 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002071 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002072 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002073 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002074 }
2075
Johan Hedberg4ae14302013-01-20 14:27:13 +02002076 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2077 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2078 MGMT_STATUS_INVALID_PARAMS);
2079
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002080 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002081 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002082
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002083 for (i = 0; i < key_count; i++) {
2084 struct mgmt_link_key_info *key = &cp->keys[i];
2085
2086 if (key->addr.type != BDADDR_BREDR)
2087 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2088 MGMT_STATUS_INVALID_PARAMS);
2089 }
2090
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002091 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002092
2093 hci_link_keys_clear(hdev);
2094
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002095 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002096 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002097 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002098 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002099
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002100 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002101 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002102
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002103 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002104 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002105 }
2106
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002107 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002108
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002109 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002110
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002111 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002112}
2113
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002114static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002115 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002116{
2117 struct mgmt_ev_device_unpaired ev;
2118
2119 bacpy(&ev.addr.bdaddr, bdaddr);
2120 ev.addr.type = addr_type;
2121
2122 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002123 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002124}
2125
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002126static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002127 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002128{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002129 struct mgmt_cp_unpair_device *cp = data;
2130 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002131 struct hci_cp_disconnect dc;
2132 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002133 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002134 int err;
2135
Johan Hedberga8a1d192011-11-10 15:54:38 +02002136 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002137 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2138 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002139
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002140 if (!bdaddr_type_is_valid(cp->addr.type))
2141 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2142 MGMT_STATUS_INVALID_PARAMS,
2143 &rp, sizeof(rp));
2144
Johan Hedberg118da702013-01-20 14:27:20 +02002145 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2146 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2147 MGMT_STATUS_INVALID_PARAMS,
2148 &rp, sizeof(rp));
2149
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002150 hci_dev_lock(hdev);
2151
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002152 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002153 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002154 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002155 goto unlock;
2156 }
2157
Andre Guedes591f47f2012-04-24 21:02:49 -03002158 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02002159 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
2160 else
2161 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002162
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002163 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002164 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002165 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002166 goto unlock;
2167 }
2168
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002169 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002170 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002171 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002172 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002173 else
2174 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002175 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002176 } else {
2177 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002178 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002179
Johan Hedberga8a1d192011-11-10 15:54:38 +02002180 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002181 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002182 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002183 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002184 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002185 }
2186
Johan Hedberg124f6e32012-02-09 13:50:12 +02002187 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002188 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002189 if (!cmd) {
2190 err = -ENOMEM;
2191 goto unlock;
2192 }
2193
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002194 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002195 dc.reason = 0x13; /* Remote User Terminated Connection */
2196 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2197 if (err < 0)
2198 mgmt_pending_remove(cmd);
2199
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002200unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002201 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002202 return err;
2203}
2204
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002205static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002206 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002207{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002208 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002209 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002210 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002211 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002212 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002213 int err;
2214
2215 BT_DBG("");
2216
Johan Hedberg06a63b12013-01-20 14:27:21 +02002217 memset(&rp, 0, sizeof(rp));
2218 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2219 rp.addr.type = cp->addr.type;
2220
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002221 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002222 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2223 MGMT_STATUS_INVALID_PARAMS,
2224 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002225
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002226 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002227
2228 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002229 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2230 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002231 goto failed;
2232 }
2233
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002234 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002235 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2236 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002237 goto failed;
2238 }
2239
Andre Guedes591f47f2012-04-24 21:02:49 -03002240 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002241 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2242 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002243 else
2244 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002245
Vishal Agarwalf9607272012-06-13 05:32:43 +05302246 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002247 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2248 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002249 goto failed;
2250 }
2251
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002252 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002253 if (!cmd) {
2254 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002255 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002256 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002257
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002258 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002259 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002260
2261 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2262 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002263 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002264
2265failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002266 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002267 return err;
2268}
2269
Andre Guedes57c14772012-04-24 21:02:50 -03002270static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002271{
2272 switch (link_type) {
2273 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002274 switch (addr_type) {
2275 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002276 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002277
Johan Hedberg48264f02011-11-09 13:58:58 +02002278 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002279 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002280 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002281 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002282
Johan Hedberg4c659c32011-11-07 23:13:39 +02002283 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002284 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002285 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002286 }
2287}
2288
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002289static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2290 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002291{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002292 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002293 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002294 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002295 int err;
2296 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002297
2298 BT_DBG("");
2299
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002300 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002301
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002302 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002303 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002304 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002305 goto unlock;
2306 }
2307
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002308 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002309 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2310 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002311 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002312 }
2313
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002314 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002315 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002316 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002317 err = -ENOMEM;
2318 goto unlock;
2319 }
2320
Johan Hedberg2784eb42011-01-21 13:56:35 +02002321 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002322 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002323 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2324 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002325 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002326 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002327 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002328 continue;
2329 i++;
2330 }
2331
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002332 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002333
Johan Hedberg4c659c32011-11-07 23:13:39 +02002334 /* Recalculate length in case of filtered SCO connections, etc */
2335 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002336
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002337 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002338 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002339
Johan Hedberga38528f2011-01-22 06:46:43 +02002340 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002341
2342unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002343 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002344 return err;
2345}
2346
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002347static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002348 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002349{
2350 struct pending_cmd *cmd;
2351 int err;
2352
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002353 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002354 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002355 if (!cmd)
2356 return -ENOMEM;
2357
Johan Hedbergd8457692012-02-17 14:24:57 +02002358 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002359 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002360 if (err < 0)
2361 mgmt_pending_remove(cmd);
2362
2363 return err;
2364}
2365
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002366static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002367 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002368{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002369 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002370 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002371 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002372 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002373 int err;
2374
2375 BT_DBG("");
2376
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002377 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002378
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002379 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002380 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002381 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002382 goto failed;
2383 }
2384
Johan Hedbergd8457692012-02-17 14:24:57 +02002385 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002386 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002387 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002388 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002389 goto failed;
2390 }
2391
2392 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002393 struct mgmt_cp_pin_code_neg_reply ncp;
2394
2395 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002396
2397 BT_ERR("PIN code is not 16 bytes long");
2398
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002399 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002400 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002401 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002402 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002403
2404 goto failed;
2405 }
2406
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002407 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002408 if (!cmd) {
2409 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002410 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002411 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002412
Johan Hedbergd8457692012-02-17 14:24:57 +02002413 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002414 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002415 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002416
2417 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2418 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002419 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002420
2421failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002422 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002423 return err;
2424}
2425
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002426static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2427 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002428{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002429 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002430
2431 BT_DBG("");
2432
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002433 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002434
2435 hdev->io_capability = cp->io_capability;
2436
2437 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002438 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002439
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002440 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002441
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002442 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2443 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002444}
2445
Gustavo Padovan6039aa732012-05-23 04:04:18 -03002446static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002447{
2448 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002449 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002450
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002451 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002452 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2453 continue;
2454
Johan Hedberge9a416b2011-02-19 12:05:56 -03002455 if (cmd->user_data != conn)
2456 continue;
2457
2458 return cmd;
2459 }
2460
2461 return NULL;
2462}
2463
2464static void pairing_complete(struct pending_cmd *cmd, u8 status)
2465{
2466 struct mgmt_rp_pair_device rp;
2467 struct hci_conn *conn = cmd->user_data;
2468
Johan Hedbergba4e5642011-11-11 00:07:34 +02002469 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002470 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002471
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002472 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002473 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002474
2475 /* So we don't get further callbacks for this connection */
2476 conn->connect_cfm_cb = NULL;
2477 conn->security_cfm_cb = NULL;
2478 conn->disconn_cfm_cb = NULL;
2479
David Herrmann76a68ba2013-04-06 20:28:37 +02002480 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002481
Johan Hedberga664b5b2011-02-19 12:06:02 -03002482 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002483}
2484
2485static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2486{
2487 struct pending_cmd *cmd;
2488
2489 BT_DBG("status %u", status);
2490
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002491 cmd = find_pairing(conn);
2492 if (!cmd)
2493 BT_DBG("Unable to find a pending command");
2494 else
Johan Hedberge2113262012-02-18 15:20:03 +02002495 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002496}
2497
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302498static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2499{
2500 struct pending_cmd *cmd;
2501
2502 BT_DBG("status %u", status);
2503
2504 if (!status)
2505 return;
2506
2507 cmd = find_pairing(conn);
2508 if (!cmd)
2509 BT_DBG("Unable to find a pending command");
2510 else
2511 pairing_complete(cmd, mgmt_status(status));
2512}
2513
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002514static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002515 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002516{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002517 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002518 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002519 struct pending_cmd *cmd;
2520 u8 sec_level, auth_type;
2521 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002522 int err;
2523
2524 BT_DBG("");
2525
Szymon Jancf950a30e2013-01-18 12:48:07 +01002526 memset(&rp, 0, sizeof(rp));
2527 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2528 rp.addr.type = cp->addr.type;
2529
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002530 if (!bdaddr_type_is_valid(cp->addr.type))
2531 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2532 MGMT_STATUS_INVALID_PARAMS,
2533 &rp, sizeof(rp));
2534
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002535 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002536
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002537 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002538 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2539 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002540 goto unlock;
2541 }
2542
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002543 sec_level = BT_SECURITY_MEDIUM;
2544 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002545 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002546 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002547 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002548
Andre Guedes591f47f2012-04-24 21:02:49 -03002549 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002550 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2551 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002552 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002553 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2554 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002555
Ville Tervo30e76272011-02-22 16:10:53 -03002556 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002557 int status;
2558
2559 if (PTR_ERR(conn) == -EBUSY)
2560 status = MGMT_STATUS_BUSY;
2561 else
2562 status = MGMT_STATUS_CONNECT_FAILED;
2563
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002564 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002565 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002566 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002567 goto unlock;
2568 }
2569
2570 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002571 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002572 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002573 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002574 goto unlock;
2575 }
2576
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002577 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002578 if (!cmd) {
2579 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002580 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002581 goto unlock;
2582 }
2583
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002584 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002585 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002586 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302587 else
2588 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002589
Johan Hedberge9a416b2011-02-19 12:05:56 -03002590 conn->security_cfm_cb = pairing_complete_cb;
2591 conn->disconn_cfm_cb = pairing_complete_cb;
2592 conn->io_capability = cp->io_cap;
2593 cmd->user_data = conn;
2594
2595 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002596 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002597 pairing_complete(cmd, 0);
2598
2599 err = 0;
2600
2601unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002602 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002603 return err;
2604}
2605
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002606static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2607 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002608{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002609 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002610 struct pending_cmd *cmd;
2611 struct hci_conn *conn;
2612 int err;
2613
2614 BT_DBG("");
2615
Johan Hedberg28424702012-02-02 04:02:29 +02002616 hci_dev_lock(hdev);
2617
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002618 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002619 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002620 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002621 goto unlock;
2622 }
2623
Johan Hedberg28424702012-02-02 04:02:29 +02002624 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2625 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002626 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002627 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002628 goto unlock;
2629 }
2630
2631 conn = cmd->user_data;
2632
2633 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002634 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002635 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002636 goto unlock;
2637 }
2638
2639 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2640
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002641 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002642 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002643unlock:
2644 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002645 return err;
2646}
2647
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002648static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002649 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002650 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002651{
Johan Hedberga5c29682011-02-19 12:05:57 -03002652 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002653 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002654 int err;
2655
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002656 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002657
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002658 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002659 err = cmd_complete(sk, hdev->id, mgmt_op,
2660 MGMT_STATUS_NOT_POWERED, addr,
2661 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002662 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002663 }
2664
Johan Hedberg1707c602013-03-15 17:07:15 -05002665 if (addr->type == BDADDR_BREDR)
2666 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002667 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002668 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002669
Johan Hedberg272d90d2012-02-09 15:26:12 +02002670 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002671 err = cmd_complete(sk, hdev->id, mgmt_op,
2672 MGMT_STATUS_NOT_CONNECTED, addr,
2673 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002674 goto done;
2675 }
2676
Johan Hedberg1707c602013-03-15 17:07:15 -05002677 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002678 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002679 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002680
Brian Gix5fe57d92011-12-21 16:12:13 -08002681 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002682 err = cmd_complete(sk, hdev->id, mgmt_op,
2683 MGMT_STATUS_SUCCESS, addr,
2684 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002685 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002686 err = cmd_complete(sk, hdev->id, mgmt_op,
2687 MGMT_STATUS_FAILED, addr,
2688 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002689
Brian Gix47c15e22011-11-16 13:53:14 -08002690 goto done;
2691 }
2692
Johan Hedberg1707c602013-03-15 17:07:15 -05002693 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002694 if (!cmd) {
2695 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002696 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002697 }
2698
Brian Gix0df4c182011-11-16 13:53:13 -08002699 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002700 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2701 struct hci_cp_user_passkey_reply cp;
2702
Johan Hedberg1707c602013-03-15 17:07:15 -05002703 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002704 cp.passkey = passkey;
2705 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2706 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002707 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2708 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002709
Johan Hedberga664b5b2011-02-19 12:06:02 -03002710 if (err < 0)
2711 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002712
Brian Gix0df4c182011-11-16 13:53:13 -08002713done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002714 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002715 return err;
2716}
2717
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302718static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2719 void *data, u16 len)
2720{
2721 struct mgmt_cp_pin_code_neg_reply *cp = data;
2722
2723 BT_DBG("");
2724
Johan Hedberg1707c602013-03-15 17:07:15 -05002725 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302726 MGMT_OP_PIN_CODE_NEG_REPLY,
2727 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2728}
2729
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002730static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2731 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002732{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002733 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002734
2735 BT_DBG("");
2736
2737 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002738 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002739 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002740
Johan Hedberg1707c602013-03-15 17:07:15 -05002741 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002742 MGMT_OP_USER_CONFIRM_REPLY,
2743 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002744}
2745
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002746static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002747 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002748{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002749 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002750
2751 BT_DBG("");
2752
Johan Hedberg1707c602013-03-15 17:07:15 -05002753 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002754 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2755 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002756}
2757
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002758static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2759 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002760{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002761 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002762
2763 BT_DBG("");
2764
Johan Hedberg1707c602013-03-15 17:07:15 -05002765 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002766 MGMT_OP_USER_PASSKEY_REPLY,
2767 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002768}
2769
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002770static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002771 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002772{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002773 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002774
2775 BT_DBG("");
2776
Johan Hedberg1707c602013-03-15 17:07:15 -05002777 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002778 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2779 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002780}
2781
Johan Hedberg13928972013-03-15 17:07:00 -05002782static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002783{
Johan Hedberg13928972013-03-15 17:07:00 -05002784 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002785 struct hci_cp_write_local_name cp;
2786
Johan Hedberg13928972013-03-15 17:07:00 -05002787 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002788
Johan Hedberg890ea892013-03-15 17:06:52 -05002789 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002790}
2791
Johan Hedberg13928972013-03-15 17:07:00 -05002792static void set_name_complete(struct hci_dev *hdev, u8 status)
2793{
2794 struct mgmt_cp_set_local_name *cp;
2795 struct pending_cmd *cmd;
2796
2797 BT_DBG("status 0x%02x", status);
2798
2799 hci_dev_lock(hdev);
2800
2801 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2802 if (!cmd)
2803 goto unlock;
2804
2805 cp = cmd->param;
2806
2807 if (status)
2808 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2809 mgmt_status(status));
2810 else
2811 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2812 cp, sizeof(*cp));
2813
2814 mgmt_pending_remove(cmd);
2815
2816unlock:
2817 hci_dev_unlock(hdev);
2818}
2819
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002820static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002821 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002822{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002823 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002824 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002825 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002826 int err;
2827
2828 BT_DBG("");
2829
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002830 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002831
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002832 /* If the old values are the same as the new ones just return a
2833 * direct command complete event.
2834 */
2835 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2836 !memcmp(hdev->short_name, cp->short_name,
2837 sizeof(hdev->short_name))) {
2838 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2839 data, len);
2840 goto failed;
2841 }
2842
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002843 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002844
Johan Hedbergb5235a62012-02-21 14:32:24 +02002845 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002846 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002847
2848 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002849 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002850 if (err < 0)
2851 goto failed;
2852
2853 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002854 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002855
Johan Hedbergb5235a62012-02-21 14:32:24 +02002856 goto failed;
2857 }
2858
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002859 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002860 if (!cmd) {
2861 err = -ENOMEM;
2862 goto failed;
2863 }
2864
Johan Hedberg13928972013-03-15 17:07:00 -05002865 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2866
Johan Hedberg890ea892013-03-15 17:06:52 -05002867 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002868
2869 if (lmp_bredr_capable(hdev)) {
2870 update_name(&req);
2871 update_eir(&req);
2872 }
2873
2874 if (lmp_le_capable(hdev))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002875 update_ad(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05002876
Johan Hedberg13928972013-03-15 17:07:00 -05002877 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002878 if (err < 0)
2879 mgmt_pending_remove(cmd);
2880
2881failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002882 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002883 return err;
2884}
2885
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002886static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002887 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002888{
Szymon Jancc35938b2011-03-22 13:12:21 +01002889 struct pending_cmd *cmd;
2890 int err;
2891
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002892 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002893
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002894 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002895
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002896 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002897 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002898 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002899 goto unlock;
2900 }
2901
Andre Guedes9a1a1992012-07-24 15:03:48 -03002902 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002903 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002904 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002905 goto unlock;
2906 }
2907
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002908 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002909 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002910 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002911 goto unlock;
2912 }
2913
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002914 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002915 if (!cmd) {
2916 err = -ENOMEM;
2917 goto unlock;
2918 }
2919
2920 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2921 if (err < 0)
2922 mgmt_pending_remove(cmd);
2923
2924unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002925 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002926 return err;
2927}
2928
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002929static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002930 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002931{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002932 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002933 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002934 int err;
2935
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002936 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002937
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002938 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002939
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002940 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002941 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002942 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002943 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002944 else
Szymon Janca6785be2012-12-13 15:11:21 +01002945 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002946
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002947 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002948 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002949
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002950 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002951 return err;
2952}
2953
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002954static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002955 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002956{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002957 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002958 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002959 int err;
2960
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002961 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002962
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002963 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002964
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002965 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002966 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002967 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002968 else
Szymon Janca6785be2012-12-13 15:11:21 +01002969 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002970
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002971 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002972 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002973
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002974 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002975 return err;
2976}
2977
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002978static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2979{
2980 struct pending_cmd *cmd;
2981 u8 type;
2982 int err;
2983
2984 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2985
2986 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2987 if (!cmd)
2988 return -ENOENT;
2989
2990 type = hdev->discovery.type;
2991
2992 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2993 &type, sizeof(type));
2994 mgmt_pending_remove(cmd);
2995
2996 return err;
2997}
2998
Andre Guedes7c307722013-04-30 15:29:28 -03002999static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3000{
3001 BT_DBG("status %d", status);
3002
3003 if (status) {
3004 hci_dev_lock(hdev);
3005 mgmt_start_discovery_failed(hdev, status);
3006 hci_dev_unlock(hdev);
3007 return;
3008 }
3009
3010 hci_dev_lock(hdev);
3011 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3012 hci_dev_unlock(hdev);
3013
3014 switch (hdev->discovery.type) {
3015 case DISCOV_TYPE_LE:
3016 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003017 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003018 break;
3019
3020 case DISCOV_TYPE_INTERLEAVED:
3021 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003022 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003023 break;
3024
3025 case DISCOV_TYPE_BREDR:
3026 break;
3027
3028 default:
3029 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3030 }
3031}
3032
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003033static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003034 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003035{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003036 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003037 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003038 struct hci_cp_le_set_scan_param param_cp;
3039 struct hci_cp_le_set_scan_enable enable_cp;
3040 struct hci_cp_inquiry inq_cp;
3041 struct hci_request req;
3042 /* General inquiry access code (GIAC) */
3043 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003044 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003045 int err;
3046
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003047 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003048
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003049 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003050
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003051 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003052 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003053 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003054 goto failed;
3055 }
3056
Andre Guedes642be6c2012-03-21 00:03:37 -03003057 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3058 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3059 MGMT_STATUS_BUSY);
3060 goto failed;
3061 }
3062
Johan Hedbergff9ef572012-01-04 14:23:45 +02003063 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003064 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003065 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003066 goto failed;
3067 }
3068
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003069 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003070 if (!cmd) {
3071 err = -ENOMEM;
3072 goto failed;
3073 }
3074
Andre Guedes4aab14e2012-02-17 20:39:36 -03003075 hdev->discovery.type = cp->type;
3076
Andre Guedes7c307722013-04-30 15:29:28 -03003077 hci_req_init(&req, hdev);
3078
Andre Guedes4aab14e2012-02-17 20:39:36 -03003079 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003080 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003081 status = mgmt_bredr_support(hdev);
3082 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003083 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003084 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003085 mgmt_pending_remove(cmd);
3086 goto failed;
3087 }
3088
Andre Guedes7c307722013-04-30 15:29:28 -03003089 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3090 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3091 MGMT_STATUS_BUSY);
3092 mgmt_pending_remove(cmd);
3093 goto failed;
3094 }
3095
3096 hci_inquiry_cache_flush(hdev);
3097
3098 memset(&inq_cp, 0, sizeof(inq_cp));
3099 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003100 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003101 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003102 break;
3103
3104 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003105 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003106 status = mgmt_le_support(hdev);
3107 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003108 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003109 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003110 mgmt_pending_remove(cmd);
3111 goto failed;
3112 }
3113
Andre Guedes7c307722013-04-30 15:29:28 -03003114 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003115 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003116 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3117 MGMT_STATUS_NOT_SUPPORTED);
3118 mgmt_pending_remove(cmd);
3119 goto failed;
3120 }
3121
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003122 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003123 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3124 MGMT_STATUS_REJECTED);
3125 mgmt_pending_remove(cmd);
3126 goto failed;
3127 }
3128
3129 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3130 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3131 MGMT_STATUS_BUSY);
3132 mgmt_pending_remove(cmd);
3133 goto failed;
3134 }
3135
3136 memset(&param_cp, 0, sizeof(param_cp));
3137 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003138 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3139 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07003140 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
3141 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
3142 else
3143 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03003144 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3145 &param_cp);
3146
3147 memset(&enable_cp, 0, sizeof(enable_cp));
3148 enable_cp.enable = LE_SCAN_ENABLE;
3149 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3150 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3151 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003152 break;
3153
Andre Guedesf39799f2012-02-17 20:39:35 -03003154 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003155 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3156 MGMT_STATUS_INVALID_PARAMS);
3157 mgmt_pending_remove(cmd);
3158 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003159 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003160
Andre Guedes7c307722013-04-30 15:29:28 -03003161 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003162 if (err < 0)
3163 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003164 else
3165 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003166
3167failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003168 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003169 return err;
3170}
3171
Andre Guedes1183fdc2013-04-30 15:29:35 -03003172static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3173{
3174 struct pending_cmd *cmd;
3175 int err;
3176
3177 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3178 if (!cmd)
3179 return -ENOENT;
3180
3181 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3182 &hdev->discovery.type, sizeof(hdev->discovery.type));
3183 mgmt_pending_remove(cmd);
3184
3185 return err;
3186}
3187
Andre Guedes0e05bba2013-04-30 15:29:33 -03003188static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3189{
3190 BT_DBG("status %d", status);
3191
3192 hci_dev_lock(hdev);
3193
3194 if (status) {
3195 mgmt_stop_discovery_failed(hdev, status);
3196 goto unlock;
3197 }
3198
3199 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3200
3201unlock:
3202 hci_dev_unlock(hdev);
3203}
3204
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003205static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003206 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003207{
Johan Hedbergd9306502012-02-20 23:25:18 +02003208 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003209 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003210 struct hci_cp_remote_name_req_cancel cp;
3211 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003212 struct hci_request req;
3213 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003214 int err;
3215
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003216 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003217
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003218 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003219
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003220 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003221 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003222 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3223 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003224 goto unlock;
3225 }
3226
3227 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003228 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003229 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3230 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003231 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003232 }
3233
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003234 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003235 if (!cmd) {
3236 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003237 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003238 }
3239
Andre Guedes0e05bba2013-04-30 15:29:33 -03003240 hci_req_init(&req, hdev);
3241
Andre Guedese0d9727e2012-03-20 15:15:36 -03003242 switch (hdev->discovery.state) {
3243 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003244 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3245 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3246 } else {
3247 cancel_delayed_work(&hdev->le_scan_disable);
3248
3249 memset(&enable_cp, 0, sizeof(enable_cp));
3250 enable_cp.enable = LE_SCAN_DISABLE;
3251 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3252 sizeof(enable_cp), &enable_cp);
3253 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003254
Andre Guedese0d9727e2012-03-20 15:15:36 -03003255 break;
3256
3257 case DISCOVERY_RESOLVING:
3258 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003259 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003260 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003261 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003262 err = cmd_complete(sk, hdev->id,
3263 MGMT_OP_STOP_DISCOVERY, 0,
3264 &mgmt_cp->type,
3265 sizeof(mgmt_cp->type));
3266 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3267 goto unlock;
3268 }
3269
3270 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003271 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3272 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003273
3274 break;
3275
3276 default:
3277 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003278
3279 mgmt_pending_remove(cmd);
3280 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3281 MGMT_STATUS_FAILED, &mgmt_cp->type,
3282 sizeof(mgmt_cp->type));
3283 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003284 }
3285
Andre Guedes0e05bba2013-04-30 15:29:33 -03003286 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003287 if (err < 0)
3288 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003289 else
3290 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003291
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003292unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003293 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003294 return err;
3295}
3296
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003297static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003298 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003299{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003300 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003301 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003302 int err;
3303
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003304 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003305
Johan Hedberg561aafb2012-01-04 13:31:59 +02003306 hci_dev_lock(hdev);
3307
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003308 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003309 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003310 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003311 goto failed;
3312 }
3313
Johan Hedberga198e7b2012-02-17 14:27:06 +02003314 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003315 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003316 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003317 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003318 goto failed;
3319 }
3320
3321 if (cp->name_known) {
3322 e->name_state = NAME_KNOWN;
3323 list_del(&e->list);
3324 } else {
3325 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003326 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003327 }
3328
Johan Hedberge3846622013-01-09 15:29:33 +02003329 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3330 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003331
3332failed:
3333 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003334 return err;
3335}
3336
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003337static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003338 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003339{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003340 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003341 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003342 int err;
3343
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003344 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003345
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003346 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003347 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3348 MGMT_STATUS_INVALID_PARAMS,
3349 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003350
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003351 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003352
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003353 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003354 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003355 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003356 else
Szymon Janca6785be2012-12-13 15:11:21 +01003357 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003358
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003359 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003360 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003361
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003362 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003363
3364 return err;
3365}
3366
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003367static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003368 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003369{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003370 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003371 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003372 int err;
3373
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003374 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003375
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003376 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003377 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3378 MGMT_STATUS_INVALID_PARAMS,
3379 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003380
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003381 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003382
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003383 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003384 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003385 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003386 else
Szymon Janca6785be2012-12-13 15:11:21 +01003387 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003388
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003389 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003390 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003391
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003392 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003393
3394 return err;
3395}
3396
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003397static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3398 u16 len)
3399{
3400 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003401 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003402 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003403 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003404
3405 BT_DBG("%s", hdev->name);
3406
Szymon Jancc72d4b82012-03-16 16:02:57 +01003407 source = __le16_to_cpu(cp->source);
3408
3409 if (source > 0x0002)
3410 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3411 MGMT_STATUS_INVALID_PARAMS);
3412
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003413 hci_dev_lock(hdev);
3414
Szymon Jancc72d4b82012-03-16 16:02:57 +01003415 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003416 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3417 hdev->devid_product = __le16_to_cpu(cp->product);
3418 hdev->devid_version = __le16_to_cpu(cp->version);
3419
3420 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3421
Johan Hedberg890ea892013-03-15 17:06:52 -05003422 hci_req_init(&req, hdev);
3423 update_eir(&req);
3424 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003425
3426 hci_dev_unlock(hdev);
3427
3428 return err;
3429}
3430
Johan Hedberg4375f102013-09-25 13:26:10 +03003431static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3432{
3433 struct cmd_lookup match = { NULL, hdev };
3434
3435 if (status) {
3436 u8 mgmt_err = mgmt_status(status);
3437
3438 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3439 cmd_status_rsp, &mgmt_err);
3440 return;
3441 }
3442
3443 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3444 &match);
3445
3446 new_settings(hdev, match.sk);
3447
3448 if (match.sk)
3449 sock_put(match.sk);
3450}
3451
Marcel Holtmann21b51872013-10-10 09:47:53 -07003452static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3453 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003454{
3455 struct mgmt_mode *cp = data;
3456 struct pending_cmd *cmd;
3457 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003458 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003459 int err;
3460
3461 BT_DBG("request for %s", hdev->name);
3462
Johan Hedberge6fe7982013-10-02 15:45:22 +03003463 status = mgmt_le_support(hdev);
3464 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003465 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003466 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003467
3468 if (cp->val != 0x00 && cp->val != 0x01)
3469 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3470 MGMT_STATUS_INVALID_PARAMS);
3471
3472 hci_dev_lock(hdev);
3473
3474 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003475 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003476
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003477 /* The following conditions are ones which mean that we should
3478 * not do any HCI communication but directly send a mgmt
3479 * response to user space (after toggling the flag if
3480 * necessary).
3481 */
3482 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003483 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003484 bool changed = false;
3485
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003486 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3487 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003488 changed = true;
3489 }
3490
3491 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3492 if (err < 0)
3493 goto unlock;
3494
3495 if (changed)
3496 err = new_settings(hdev, sk);
3497
3498 goto unlock;
3499 }
3500
3501 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3502 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3503 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3504 MGMT_STATUS_BUSY);
3505 goto unlock;
3506 }
3507
3508 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3509 if (!cmd) {
3510 err = -ENOMEM;
3511 goto unlock;
3512 }
3513
3514 hci_req_init(&req, hdev);
3515
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003516 if (val)
3517 enable_advertising(&req);
3518 else
3519 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003520
3521 err = hci_req_run(&req, set_advertising_complete);
3522 if (err < 0)
3523 mgmt_pending_remove(cmd);
3524
3525unlock:
3526 hci_dev_unlock(hdev);
3527 return err;
3528}
3529
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003530static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3531 void *data, u16 len)
3532{
3533 struct mgmt_cp_set_static_address *cp = data;
3534 int err;
3535
3536 BT_DBG("%s", hdev->name);
3537
Marcel Holtmann62af4442013-10-02 22:10:32 -07003538 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003539 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003540 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003541
3542 if (hdev_is_powered(hdev))
3543 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3544 MGMT_STATUS_REJECTED);
3545
3546 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3547 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3548 return cmd_status(sk, hdev->id,
3549 MGMT_OP_SET_STATIC_ADDRESS,
3550 MGMT_STATUS_INVALID_PARAMS);
3551
3552 /* Two most significant bits shall be set */
3553 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3554 return cmd_status(sk, hdev->id,
3555 MGMT_OP_SET_STATIC_ADDRESS,
3556 MGMT_STATUS_INVALID_PARAMS);
3557 }
3558
3559 hci_dev_lock(hdev);
3560
3561 bacpy(&hdev->static_addr, &cp->bdaddr);
3562
3563 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3564
3565 hci_dev_unlock(hdev);
3566
3567 return err;
3568}
3569
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003570static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3571 void *data, u16 len)
3572{
3573 struct mgmt_cp_set_scan_params *cp = data;
3574 __u16 interval, window;
3575 int err;
3576
3577 BT_DBG("%s", hdev->name);
3578
3579 if (!lmp_le_capable(hdev))
3580 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3581 MGMT_STATUS_NOT_SUPPORTED);
3582
3583 interval = __le16_to_cpu(cp->interval);
3584
3585 if (interval < 0x0004 || interval > 0x4000)
3586 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3587 MGMT_STATUS_INVALID_PARAMS);
3588
3589 window = __le16_to_cpu(cp->window);
3590
3591 if (window < 0x0004 || window > 0x4000)
3592 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3593 MGMT_STATUS_INVALID_PARAMS);
3594
Marcel Holtmann899e1072013-10-14 09:55:32 -07003595 if (window > interval)
3596 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3597 MGMT_STATUS_INVALID_PARAMS);
3598
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003599 hci_dev_lock(hdev);
3600
3601 hdev->le_scan_interval = interval;
3602 hdev->le_scan_window = window;
3603
3604 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3605
3606 hci_dev_unlock(hdev);
3607
3608 return err;
3609}
3610
Johan Hedberg33e38b32013-03-15 17:07:05 -05003611static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3612{
3613 struct pending_cmd *cmd;
3614
3615 BT_DBG("status 0x%02x", status);
3616
3617 hci_dev_lock(hdev);
3618
3619 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3620 if (!cmd)
3621 goto unlock;
3622
3623 if (status) {
3624 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3625 mgmt_status(status));
3626 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003627 struct mgmt_mode *cp = cmd->param;
3628
3629 if (cp->val)
3630 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3631 else
3632 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3633
Johan Hedberg33e38b32013-03-15 17:07:05 -05003634 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3635 new_settings(hdev, cmd->sk);
3636 }
3637
3638 mgmt_pending_remove(cmd);
3639
3640unlock:
3641 hci_dev_unlock(hdev);
3642}
3643
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003644static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003645 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003646{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003647 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003648 struct pending_cmd *cmd;
3649 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003650 int err;
3651
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003652 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003653
Johan Hedberg56f87902013-10-02 13:43:13 +03003654 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3655 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003656 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3657 MGMT_STATUS_NOT_SUPPORTED);
3658
Johan Hedberga7e80f22013-01-09 16:05:19 +02003659 if (cp->val != 0x00 && cp->val != 0x01)
3660 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3661 MGMT_STATUS_INVALID_PARAMS);
3662
Johan Hedberg5400c042012-02-21 16:40:33 +02003663 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003664 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003665 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003666
3667 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003668 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003669 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003670
3671 hci_dev_lock(hdev);
3672
Johan Hedberg05cbf292013-03-15 17:07:07 -05003673 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3674 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3675 MGMT_STATUS_BUSY);
3676 goto unlock;
3677 }
3678
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003679 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3680 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3681 hdev);
3682 goto unlock;
3683 }
3684
Johan Hedberg33e38b32013-03-15 17:07:05 -05003685 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3686 data, len);
3687 if (!cmd) {
3688 err = -ENOMEM;
3689 goto unlock;
3690 }
3691
3692 hci_req_init(&req, hdev);
3693
Johan Hedberg406d7802013-03-15 17:07:09 -05003694 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003695
3696 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003697 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003698 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003699 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003700 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003701 }
3702
Johan Hedberg33e38b32013-03-15 17:07:05 -05003703unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003704 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003705
Antti Julkuf6422ec2011-06-22 13:11:56 +03003706 return err;
3707}
3708
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003709static void set_bredr_scan(struct hci_request *req)
3710{
3711 struct hci_dev *hdev = req->hdev;
3712 u8 scan = 0;
3713
3714 /* Ensure that fast connectable is disabled. This function will
3715 * not do anything if the page scan parameters are already what
3716 * they should be.
3717 */
3718 write_fast_connectable(req, false);
3719
3720 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3721 scan |= SCAN_PAGE;
3722 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3723 scan |= SCAN_INQUIRY;
3724
3725 if (scan)
3726 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3727}
3728
Johan Hedberg0663ca22013-10-02 13:43:14 +03003729static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3730{
3731 struct pending_cmd *cmd;
3732
3733 BT_DBG("status 0x%02x", status);
3734
3735 hci_dev_lock(hdev);
3736
3737 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3738 if (!cmd)
3739 goto unlock;
3740
3741 if (status) {
3742 u8 mgmt_err = mgmt_status(status);
3743
3744 /* We need to restore the flag if related HCI commands
3745 * failed.
3746 */
3747 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3748
3749 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3750 } else {
3751 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3752 new_settings(hdev, cmd->sk);
3753 }
3754
3755 mgmt_pending_remove(cmd);
3756
3757unlock:
3758 hci_dev_unlock(hdev);
3759}
3760
3761static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3762{
3763 struct mgmt_mode *cp = data;
3764 struct pending_cmd *cmd;
3765 struct hci_request req;
3766 int err;
3767
3768 BT_DBG("request for %s", hdev->name);
3769
3770 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3771 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3772 MGMT_STATUS_NOT_SUPPORTED);
3773
3774 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3775 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3776 MGMT_STATUS_REJECTED);
3777
3778 if (cp->val != 0x00 && cp->val != 0x01)
3779 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3780 MGMT_STATUS_INVALID_PARAMS);
3781
3782 hci_dev_lock(hdev);
3783
3784 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3785 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3786 goto unlock;
3787 }
3788
3789 if (!hdev_is_powered(hdev)) {
3790 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003791 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3792 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3793 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3794 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3795 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3796 }
3797
3798 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3799
3800 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3801 if (err < 0)
3802 goto unlock;
3803
3804 err = new_settings(hdev, sk);
3805 goto unlock;
3806 }
3807
3808 /* Reject disabling when powered on */
3809 if (!cp->val) {
3810 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3811 MGMT_STATUS_REJECTED);
3812 goto unlock;
3813 }
3814
3815 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3816 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3817 MGMT_STATUS_BUSY);
3818 goto unlock;
3819 }
3820
3821 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3822 if (!cmd) {
3823 err = -ENOMEM;
3824 goto unlock;
3825 }
3826
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07003827 /* We need to flip the bit already here so that update_ad
Johan Hedberg0663ca22013-10-02 13:43:14 +03003828 * generates the correct flags.
3829 */
3830 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3831
3832 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003833
3834 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3835 set_bredr_scan(&req);
3836
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07003837 update_ad(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003838
Johan Hedberg0663ca22013-10-02 13:43:14 +03003839 err = hci_req_run(&req, set_bredr_complete);
3840 if (err < 0)
3841 mgmt_pending_remove(cmd);
3842
3843unlock:
3844 hci_dev_unlock(hdev);
3845 return err;
3846}
3847
Johan Hedberg3f706b72013-01-20 14:27:16 +02003848static bool ltk_is_valid(struct mgmt_ltk_info *key)
3849{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003850 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3851 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003852 if (key->master != 0x00 && key->master != 0x01)
3853 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003854 if (!bdaddr_type_is_le(key->addr.type))
3855 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003856 return true;
3857}
3858
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003859static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003860 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003861{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003862 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3863 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003864 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003865
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003866 BT_DBG("request for %s", hdev->name);
3867
3868 if (!lmp_le_capable(hdev))
3869 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3870 MGMT_STATUS_NOT_SUPPORTED);
3871
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003872 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003873
3874 expected_len = sizeof(*cp) + key_count *
3875 sizeof(struct mgmt_ltk_info);
3876 if (expected_len != len) {
3877 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003878 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003879 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003880 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003881 }
3882
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003883 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003884
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003885 for (i = 0; i < key_count; i++) {
3886 struct mgmt_ltk_info *key = &cp->keys[i];
3887
Johan Hedberg3f706b72013-01-20 14:27:16 +02003888 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003889 return cmd_status(sk, hdev->id,
3890 MGMT_OP_LOAD_LONG_TERM_KEYS,
3891 MGMT_STATUS_INVALID_PARAMS);
3892 }
3893
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003894 hci_dev_lock(hdev);
3895
3896 hci_smp_ltks_clear(hdev);
3897
3898 for (i = 0; i < key_count; i++) {
3899 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003900 u8 type, addr_type;
3901
3902 if (key->addr.type == BDADDR_LE_PUBLIC)
3903 addr_type = ADDR_LE_DEV_PUBLIC;
3904 else
3905 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003906
3907 if (key->master)
3908 type = HCI_SMP_LTK;
3909 else
3910 type = HCI_SMP_LTK_SLAVE;
3911
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003912 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003913 type, 0, key->authenticated, key->val,
3914 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003915 }
3916
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003917 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3918 NULL, 0);
3919
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003920 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003921
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003922 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003923}
3924
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003925static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003926 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3927 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003928 bool var_len;
3929 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003930} mgmt_handlers[] = {
3931 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003932 { read_version, false, MGMT_READ_VERSION_SIZE },
3933 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3934 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3935 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3936 { set_powered, false, MGMT_SETTING_SIZE },
3937 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3938 { set_connectable, false, MGMT_SETTING_SIZE },
3939 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3940 { set_pairable, false, MGMT_SETTING_SIZE },
3941 { set_link_security, false, MGMT_SETTING_SIZE },
3942 { set_ssp, false, MGMT_SETTING_SIZE },
3943 { set_hs, false, MGMT_SETTING_SIZE },
3944 { set_le, false, MGMT_SETTING_SIZE },
3945 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3946 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3947 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3948 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3949 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3950 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3951 { disconnect, false, MGMT_DISCONNECT_SIZE },
3952 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3953 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3954 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3955 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3956 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3957 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3958 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3959 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3960 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3961 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3962 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3963 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3964 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3965 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3966 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3967 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3968 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3969 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3970 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003971 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003972 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003973 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003974 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003975 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003976};
3977
3978
Johan Hedberg03811012010-12-08 00:21:06 +02003979int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3980{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003981 void *buf;
3982 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003983 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003984 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003985 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003986 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003987 int err;
3988
3989 BT_DBG("got %zu bytes", msglen);
3990
3991 if (msglen < sizeof(*hdr))
3992 return -EINVAL;
3993
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003994 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003995 if (!buf)
3996 return -ENOMEM;
3997
3998 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3999 err = -EFAULT;
4000 goto done;
4001 }
4002
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004003 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004004 opcode = __le16_to_cpu(hdr->opcode);
4005 index = __le16_to_cpu(hdr->index);
4006 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004007
4008 if (len != msglen - sizeof(*hdr)) {
4009 err = -EINVAL;
4010 goto done;
4011 }
4012
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004013 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004014 hdev = hci_dev_get(index);
4015 if (!hdev) {
4016 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004017 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004018 goto done;
4019 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004020
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004021 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4022 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004023 err = cmd_status(sk, index, opcode,
4024 MGMT_STATUS_INVALID_INDEX);
4025 goto done;
4026 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004027 }
4028
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004029 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004030 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004031 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004032 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004033 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004034 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004035 }
4036
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004037 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004038 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004039 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004040 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004041 goto done;
4042 }
4043
Johan Hedbergbe22b542012-03-01 22:24:41 +02004044 handler = &mgmt_handlers[opcode];
4045
4046 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004047 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004048 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004049 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004050 goto done;
4051 }
4052
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004053 if (hdev)
4054 mgmt_init_hdev(sk, hdev);
4055
4056 cp = buf + sizeof(*hdr);
4057
Johan Hedbergbe22b542012-03-01 22:24:41 +02004058 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004059 if (err < 0)
4060 goto done;
4061
Johan Hedberg03811012010-12-08 00:21:06 +02004062 err = msglen;
4063
4064done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004065 if (hdev)
4066 hci_dev_put(hdev);
4067
Johan Hedberg03811012010-12-08 00:21:06 +02004068 kfree(buf);
4069 return err;
4070}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004071
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004072void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004073{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004074 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004075 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004076
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004077 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004078}
4079
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004080void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004081{
Johan Hedberg5f159032012-03-02 03:13:19 +02004082 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004083
Marcel Holtmann1514b892013-10-06 08:25:01 -07004084 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004085 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004086
Johan Hedberg744cf192011-11-08 20:40:14 +02004087 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004088
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004089 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004090}
4091
Johan Hedberg229ab392013-03-15 17:06:53 -05004092static void powered_complete(struct hci_dev *hdev, u8 status)
4093{
4094 struct cmd_lookup match = { NULL, hdev };
4095
4096 BT_DBG("status 0x%02x", status);
4097
4098 hci_dev_lock(hdev);
4099
4100 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4101
4102 new_settings(hdev, match.sk);
4103
4104 hci_dev_unlock(hdev);
4105
4106 if (match.sk)
4107 sock_put(match.sk);
4108}
4109
Johan Hedberg70da6242013-03-15 17:06:51 -05004110static int powered_update_hci(struct hci_dev *hdev)
4111{
Johan Hedberg890ea892013-03-15 17:06:52 -05004112 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004113 u8 link_sec;
4114
Johan Hedberg890ea892013-03-15 17:06:52 -05004115 hci_req_init(&req, hdev);
4116
Johan Hedberg70da6242013-03-15 17:06:51 -05004117 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4118 !lmp_host_ssp_capable(hdev)) {
4119 u8 ssp = 1;
4120
Johan Hedberg890ea892013-03-15 17:06:52 -05004121 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004122 }
4123
Johan Hedbergc73eee92013-04-19 18:35:21 +03004124 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4125 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004126 struct hci_cp_write_le_host_supported cp;
4127
4128 cp.le = 1;
4129 cp.simul = lmp_le_br_capable(hdev);
4130
4131 /* Check first if we already have the right
4132 * host state (host features set)
4133 */
4134 if (cp.le != lmp_host_le_capable(hdev) ||
4135 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004136 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4137 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004138 }
4139
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004140 if (lmp_le_capable(hdev)) {
4141 /* Set random address to static address if configured */
4142 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4143 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4144 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004145
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004146 /* Make sure the controller has a good default for
4147 * advertising data. This also applies to the case
4148 * where BR/EDR was toggled during the AUTO_OFF phase.
4149 */
4150 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
4151 update_ad(&req);
4152
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004153 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4154 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004155 }
4156
Johan Hedberg70da6242013-03-15 17:06:51 -05004157 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4158 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004159 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4160 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004161
4162 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004163 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4164 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004165 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004166 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004167 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004168 }
4169
Johan Hedberg229ab392013-03-15 17:06:53 -05004170 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004171}
4172
Johan Hedberg744cf192011-11-08 20:40:14 +02004173int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004174{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004175 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004176 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4177 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004178 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004179
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004180 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4181 return 0;
4182
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004183 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004184 if (powered_update_hci(hdev) == 0)
4185 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004186
Johan Hedberg229ab392013-03-15 17:06:53 -05004187 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4188 &match);
4189 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004190 }
4191
Johan Hedberg229ab392013-03-15 17:06:53 -05004192 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4193 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4194
4195 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4196 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4197 zero_cod, sizeof(zero_cod), NULL);
4198
4199new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004200 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004201
4202 if (match.sk)
4203 sock_put(match.sk);
4204
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004205 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004206}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004207
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004208void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004209{
4210 struct pending_cmd *cmd;
4211 u8 status;
4212
4213 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4214 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004215 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004216
4217 if (err == -ERFKILL)
4218 status = MGMT_STATUS_RFKILLED;
4219 else
4220 status = MGMT_STATUS_FAILED;
4221
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004222 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004223
4224 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004225}
4226
Johan Hedberg744cf192011-11-08 20:40:14 +02004227int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004228{
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004229 bool changed = false;
4230 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004231
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004232 /* Nothing needed here if there's a pending command since that
4233 * commands request completion callback takes care of everything
4234 * necessary.
4235 */
4236 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
4237 return 0;
4238
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004239 if (discoverable) {
4240 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4241 changed = true;
4242 } else {
4243 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4244 changed = true;
4245 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004246
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004247 if (changed)
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004248 err = new_settings(hdev, NULL);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004249
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004250 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004251}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004252
Johan Hedberg744cf192011-11-08 20:40:14 +02004253int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004254{
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004255 bool changed = false;
4256 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004257
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004258 /* Nothing needed here if there's a pending command since that
4259 * commands request completion callback takes care of everything
4260 * necessary.
4261 */
4262 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
4263 return 0;
4264
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004265 if (connectable) {
4266 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4267 changed = true;
4268 } else {
4269 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4270 changed = true;
4271 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004272
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004273 if (changed)
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004274 err = new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004275
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004276 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004277}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004278
Johan Hedberg744cf192011-11-08 20:40:14 +02004279int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004280{
Johan Hedbergca69b792011-11-11 18:10:00 +02004281 u8 mgmt_err = mgmt_status(status);
4282
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004283 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004284 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004285 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004286
4287 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004288 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004289 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004290
4291 return 0;
4292}
4293
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004294int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4295 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004296{
Johan Hedberg86742e12011-11-07 23:13:38 +02004297 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004298
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004299 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004300
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004301 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004302 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004303 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004304 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004305 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004306 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004307
Johan Hedberg744cf192011-11-08 20:40:14 +02004308 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004309}
Johan Hedbergf7520542011-01-20 12:34:39 +02004310
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004311int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4312{
4313 struct mgmt_ev_new_long_term_key ev;
4314
4315 memset(&ev, 0, sizeof(ev));
4316
4317 ev.store_hint = persistent;
4318 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004319 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004320 ev.key.authenticated = key->authenticated;
4321 ev.key.enc_size = key->enc_size;
4322 ev.key.ediv = key->ediv;
4323
4324 if (key->type == HCI_SMP_LTK)
4325 ev.key.master = 1;
4326
4327 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4328 memcpy(ev.key.val, key->val, sizeof(key->val));
4329
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004330 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4331 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004332}
4333
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004334void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4335 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4336 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004337{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004338 char buf[512];
4339 struct mgmt_ev_device_connected *ev = (void *) buf;
4340 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004341
Johan Hedbergb644ba32012-01-17 21:48:47 +02004342 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004343 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004344
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004345 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004346
Johan Hedbergb644ba32012-01-17 21:48:47 +02004347 if (name_len > 0)
4348 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004349 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004350
4351 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004352 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004353 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004354
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004355 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004356
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004357 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4358 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004359}
4360
Johan Hedberg8962ee72011-01-20 12:40:27 +02004361static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4362{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004363 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004364 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004365 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004366
Johan Hedberg88c3df12012-02-09 14:27:38 +02004367 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4368 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004369
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004370 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004371 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004372
4373 *sk = cmd->sk;
4374 sock_hold(*sk);
4375
Johan Hedberga664b5b2011-02-19 12:06:02 -03004376 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004377}
4378
Johan Hedberg124f6e32012-02-09 13:50:12 +02004379static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004380{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004381 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004382 struct mgmt_cp_unpair_device *cp = cmd->param;
4383 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004384
4385 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004386 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4387 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004388
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004389 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4390
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004391 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004392
4393 mgmt_pending_remove(cmd);
4394}
4395
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004396void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4397 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004398{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004399 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004400 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004401
Johan Hedberg744cf192011-11-08 20:40:14 +02004402 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004403
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004404 bacpy(&ev.addr.bdaddr, bdaddr);
4405 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4406 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004407
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004408 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004409
4410 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004411 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004412
Johan Hedberg124f6e32012-02-09 13:50:12 +02004413 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004414 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004415}
4416
Marcel Holtmann78929242013-10-06 23:55:47 -07004417void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4418 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004419{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004420 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004421 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004422
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004423 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4424 hdev);
4425
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004426 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004427 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004428 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004429
Johan Hedberg88c3df12012-02-09 14:27:38 +02004430 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004431 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004432
Marcel Holtmann78929242013-10-06 23:55:47 -07004433 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4434 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004435
Johan Hedberga664b5b2011-02-19 12:06:02 -03004436 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004437}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004438
Marcel Holtmann445608d2013-10-06 23:55:48 -07004439void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4440 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004441{
4442 struct mgmt_ev_connect_failed ev;
4443
Johan Hedberg4c659c32011-11-07 23:13:39 +02004444 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004445 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004446 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004447
Marcel Holtmann445608d2013-10-06 23:55:48 -07004448 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004449}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004450
Johan Hedberg744cf192011-11-08 20:40:14 +02004451int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004452{
4453 struct mgmt_ev_pin_code_request ev;
4454
Johan Hedbergd8457692012-02-17 14:24:57 +02004455 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004456 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004457 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004458
Johan Hedberg744cf192011-11-08 20:40:14 +02004459 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004460 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004461}
4462
Johan Hedberg744cf192011-11-08 20:40:14 +02004463int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004464 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004465{
4466 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004467 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004468 int err;
4469
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004470 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004471 if (!cmd)
4472 return -ENOENT;
4473
Johan Hedbergd8457692012-02-17 14:24:57 +02004474 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004475 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004476
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004477 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004478 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004479
Johan Hedberga664b5b2011-02-19 12:06:02 -03004480 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004481
4482 return err;
4483}
4484
Johan Hedberg744cf192011-11-08 20:40:14 +02004485int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004486 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004487{
4488 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004489 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004490 int err;
4491
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004492 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004493 if (!cmd)
4494 return -ENOENT;
4495
Johan Hedbergd8457692012-02-17 14:24:57 +02004496 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004497 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004498
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004499 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004500 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004501
Johan Hedberga664b5b2011-02-19 12:06:02 -03004502 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004503
4504 return err;
4505}
Johan Hedberga5c29682011-02-19 12:05:57 -03004506
Johan Hedberg744cf192011-11-08 20:40:14 +02004507int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004508 u8 link_type, u8 addr_type, __le32 value,
4509 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004510{
4511 struct mgmt_ev_user_confirm_request ev;
4512
Johan Hedberg744cf192011-11-08 20:40:14 +02004513 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004514
Johan Hedberg272d90d2012-02-09 15:26:12 +02004515 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004516 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004517 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02004518 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004519
Johan Hedberg744cf192011-11-08 20:40:14 +02004520 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004521 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004522}
4523
Johan Hedberg272d90d2012-02-09 15:26:12 +02004524int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004525 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004526{
4527 struct mgmt_ev_user_passkey_request ev;
4528
4529 BT_DBG("%s", hdev->name);
4530
Johan Hedberg272d90d2012-02-09 15:26:12 +02004531 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004532 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004533
4534 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004535 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004536}
4537
Brian Gix0df4c182011-11-16 13:53:13 -08004538static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004539 u8 link_type, u8 addr_type, u8 status,
4540 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004541{
4542 struct pending_cmd *cmd;
4543 struct mgmt_rp_user_confirm_reply rp;
4544 int err;
4545
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004546 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004547 if (!cmd)
4548 return -ENOENT;
4549
Johan Hedberg272d90d2012-02-09 15:26:12 +02004550 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004551 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004552 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004553 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004554
Johan Hedberga664b5b2011-02-19 12:06:02 -03004555 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004556
4557 return err;
4558}
4559
Johan Hedberg744cf192011-11-08 20:40:14 +02004560int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004561 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004562{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004563 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004564 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004565}
4566
Johan Hedberg272d90d2012-02-09 15:26:12 +02004567int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004568 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004569{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004570 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004571 status,
4572 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004573}
Johan Hedberg2a611692011-02-19 12:06:00 -03004574
Brian Gix604086b2011-11-23 08:28:33 -08004575int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004576 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004577{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004578 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004579 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004580}
4581
Johan Hedberg272d90d2012-02-09 15:26:12 +02004582int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004583 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004584{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004585 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004586 status,
4587 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004588}
4589
Johan Hedberg92a25252012-09-06 18:39:26 +03004590int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4591 u8 link_type, u8 addr_type, u32 passkey,
4592 u8 entered)
4593{
4594 struct mgmt_ev_passkey_notify ev;
4595
4596 BT_DBG("%s", hdev->name);
4597
4598 bacpy(&ev.addr.bdaddr, bdaddr);
4599 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4600 ev.passkey = __cpu_to_le32(passkey);
4601 ev.entered = entered;
4602
4603 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4604}
4605
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004606int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004607 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004608{
4609 struct mgmt_ev_auth_failed ev;
4610
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004611 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004612 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004613 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004614
Johan Hedberg744cf192011-11-08 20:40:14 +02004615 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004616}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004617
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004618int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4619{
4620 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004621 bool changed = false;
4622 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004623
4624 if (status) {
4625 u8 mgmt_err = mgmt_status(status);
4626 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004627 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004628 return 0;
4629 }
4630
Johan Hedberg47990ea2012-02-22 11:58:37 +02004631 if (test_bit(HCI_AUTH, &hdev->flags)) {
4632 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4633 changed = true;
4634 } else {
4635 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4636 changed = true;
4637 }
4638
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004639 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004640 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004641
Johan Hedberg47990ea2012-02-22 11:58:37 +02004642 if (changed)
4643 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004644
4645 if (match.sk)
4646 sock_put(match.sk);
4647
4648 return err;
4649}
4650
Johan Hedberg890ea892013-03-15 17:06:52 -05004651static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004652{
Johan Hedberg890ea892013-03-15 17:06:52 -05004653 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004654 struct hci_cp_write_eir cp;
4655
Johan Hedberg976eb202012-10-24 21:12:01 +03004656 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004657 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004658
Johan Hedbergc80da272012-02-22 15:38:48 +02004659 memset(hdev->eir, 0, sizeof(hdev->eir));
4660
Johan Hedbergcacaf522012-02-21 00:52:42 +02004661 memset(&cp, 0, sizeof(cp));
4662
Johan Hedberg890ea892013-03-15 17:06:52 -05004663 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004664}
4665
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004666int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004667{
4668 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004669 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004670 bool changed = false;
4671 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004672
4673 if (status) {
4674 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004675
4676 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004677 &hdev->dev_flags)) {
4678 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004679 err = new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004680 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004681
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004682 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4683 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004684
4685 return err;
4686 }
4687
4688 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004689 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004690 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004691 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4692 if (!changed)
4693 changed = test_and_clear_bit(HCI_HS_ENABLED,
4694 &hdev->dev_flags);
4695 else
4696 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004697 }
4698
4699 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4700
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004701 if (changed)
4702 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004703
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004704 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004705 sock_put(match.sk);
4706
Johan Hedberg890ea892013-03-15 17:06:52 -05004707 hci_req_init(&req, hdev);
4708
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004709 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004710 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004711 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004712 clear_eir(&req);
4713
4714 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004715
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004716 return err;
4717}
4718
Johan Hedberg92da6092013-03-15 17:06:55 -05004719static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004720{
4721 struct cmd_lookup *match = data;
4722
Johan Hedberg90e70452012-02-23 23:09:40 +02004723 if (match->sk == NULL) {
4724 match->sk = cmd->sk;
4725 sock_hold(match->sk);
4726 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004727}
4728
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004729int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004730 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004731{
Johan Hedberg90e70452012-02-23 23:09:40 +02004732 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4733 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004734
Johan Hedberg92da6092013-03-15 17:06:55 -05004735 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4736 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4737 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004738
4739 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004740 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4741 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004742
4743 if (match.sk)
4744 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004745
4746 return err;
4747}
4748
Johan Hedberg744cf192011-11-08 20:40:14 +02004749int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004750{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004751 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004752 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004753
Johan Hedberg13928972013-03-15 17:07:00 -05004754 if (status)
4755 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004756
4757 memset(&ev, 0, sizeof(ev));
4758 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004759 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004760
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004761 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004762 if (!cmd) {
4763 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004764
Johan Hedberg13928972013-03-15 17:07:00 -05004765 /* If this is a HCI command related to powering on the
4766 * HCI dev don't send any mgmt signals.
4767 */
4768 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4769 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004770 }
4771
Johan Hedberg13928972013-03-15 17:07:00 -05004772 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4773 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004774}
Szymon Jancc35938b2011-03-22 13:12:21 +01004775
Johan Hedberg744cf192011-11-08 20:40:14 +02004776int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004777 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004778{
4779 struct pending_cmd *cmd;
4780 int err;
4781
Johan Hedberg744cf192011-11-08 20:40:14 +02004782 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004783
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004784 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004785 if (!cmd)
4786 return -ENOENT;
4787
4788 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004789 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4790 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004791 } else {
4792 struct mgmt_rp_read_local_oob_data rp;
4793
4794 memcpy(rp.hash, hash, sizeof(rp.hash));
4795 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4796
Johan Hedberg744cf192011-11-08 20:40:14 +02004797 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004798 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4799 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004800 }
4801
4802 mgmt_pending_remove(cmd);
4803
4804 return err;
4805}
Johan Hedberge17acd42011-03-30 23:57:16 +03004806
Marcel Holtmann901801b2013-10-06 23:55:51 -07004807void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4808 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4809 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004810{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004811 char buf[512];
4812 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004813 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004814
Andre Guedes12602d02013-04-30 15:29:40 -03004815 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004816 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004817
Johan Hedberg1dc06092012-01-15 21:01:23 +02004818 /* Leave 5 bytes for a potential CoD field */
4819 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004820 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004821
Johan Hedberg1dc06092012-01-15 21:01:23 +02004822 memset(buf, 0, sizeof(buf));
4823
Johan Hedberge319d2e2012-01-15 19:51:59 +02004824 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004825 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004826 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004827 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304828 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004829 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304830 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004831
Johan Hedberg1dc06092012-01-15 21:01:23 +02004832 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004833 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004834
Johan Hedberg1dc06092012-01-15 21:01:23 +02004835 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4836 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004837 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004838
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004839 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004840 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004841
Marcel Holtmann901801b2013-10-06 23:55:51 -07004842 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004843}
Johan Hedberga88a9652011-03-30 13:18:12 +03004844
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004845void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4846 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004847{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004848 struct mgmt_ev_device_found *ev;
4849 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4850 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004851
Johan Hedbergb644ba32012-01-17 21:48:47 +02004852 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004853
Johan Hedbergb644ba32012-01-17 21:48:47 +02004854 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004855
Johan Hedbergb644ba32012-01-17 21:48:47 +02004856 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004857 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004858 ev->rssi = rssi;
4859
4860 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004861 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004862
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004863 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004864
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004865 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004866}
Johan Hedberg314b2382011-04-27 10:29:57 -04004867
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004868void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004869{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004870 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004871 struct pending_cmd *cmd;
4872
Andre Guedes343fb142011-11-22 17:14:19 -03004873 BT_DBG("%s discovering %u", hdev->name, discovering);
4874
Johan Hedberg164a6e72011-11-01 17:06:44 +02004875 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004876 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004877 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004878 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004879
4880 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004881 u8 type = hdev->discovery.type;
4882
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004883 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4884 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004885 mgmt_pending_remove(cmd);
4886 }
4887
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004888 memset(&ev, 0, sizeof(ev));
4889 ev.type = hdev->discovery.type;
4890 ev.discovering = discovering;
4891
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004892 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004893}
Antti Julku5e762442011-08-25 16:48:02 +03004894
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004895int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004896{
4897 struct pending_cmd *cmd;
4898 struct mgmt_ev_device_blocked ev;
4899
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004900 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004901
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004902 bacpy(&ev.addr.bdaddr, bdaddr);
4903 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004904
Johan Hedberg744cf192011-11-08 20:40:14 +02004905 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004906 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004907}
4908
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004909int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004910{
4911 struct pending_cmd *cmd;
4912 struct mgmt_ev_device_unblocked ev;
4913
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004914 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004915
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004916 bacpy(&ev.addr.bdaddr, bdaddr);
4917 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004918
Johan Hedberg744cf192011-11-08 20:40:14 +02004919 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004920 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004921}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004922
4923static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4924{
4925 BT_DBG("%s status %u", hdev->name, status);
4926
4927 /* Clear the advertising mgmt setting if we failed to re-enable it */
4928 if (status) {
4929 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004930 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004931 }
4932}
4933
4934void mgmt_reenable_advertising(struct hci_dev *hdev)
4935{
4936 struct hci_request req;
4937
Marcel Holtmannb145edc2013-10-10 09:47:54 -07004938 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07004939 return;
4940
4941 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4942 return;
4943
4944 hci_req_init(&req, hdev);
4945 enable_advertising(&req);
4946
4947 /* If this fails we have no option but to let user space know
4948 * that we've disabled advertising.
4949 */
4950 if (hci_req_run(&req, adv_enable_complete) < 0) {
4951 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004952 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004953 }
4954}