blob: 62c5312699275dd9477b8a5d7f4de5df35642a70 [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
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700727 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
728 cod[1] |= 0x20;
729
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200730 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500731 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200732
Johan Hedberg890ea892013-03-15 17:06:52 -0500733 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200734}
735
Johan Hedberg7d785252011-12-15 00:47:39 +0200736static void service_cache_off(struct work_struct *work)
737{
738 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300739 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500740 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200741
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200742 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200743 return;
744
Johan Hedberg890ea892013-03-15 17:06:52 -0500745 hci_req_init(&req, hdev);
746
Johan Hedberg7d785252011-12-15 00:47:39 +0200747 hci_dev_lock(hdev);
748
Johan Hedberg890ea892013-03-15 17:06:52 -0500749 update_eir(&req);
750 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200751
752 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500753
754 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200755}
756
Johan Hedberg6a919082012-02-28 06:17:26 +0200757static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200758{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200759 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200760 return;
761
Johan Hedberg4f87da82012-03-02 19:55:56 +0200762 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200763
Johan Hedberg4f87da82012-03-02 19:55:56 +0200764 /* Non-mgmt controlled devices get this bit set
765 * implicitly so that pairing works for them, however
766 * for mgmt we require user-space to explicitly enable
767 * it
768 */
769 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200770}
771
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200772static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300773 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200774{
775 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200776
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200777 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200778
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300779 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200780
Johan Hedberg03811012010-12-08 00:21:06 +0200781 memset(&rp, 0, sizeof(rp));
782
Johan Hedberg03811012010-12-08 00:21:06 +0200783 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200784
785 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200786 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200787
788 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
789 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
790
791 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200792
793 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200794 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200795
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300796 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200797
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200798 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300799 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200800}
801
802static void mgmt_pending_free(struct pending_cmd *cmd)
803{
804 sock_put(cmd->sk);
805 kfree(cmd->param);
806 kfree(cmd);
807}
808
809static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300810 struct hci_dev *hdev, void *data,
811 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200812{
813 struct pending_cmd *cmd;
814
Andre Guedes12b94562012-06-07 19:05:45 -0300815 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200816 if (!cmd)
817 return NULL;
818
819 cmd->opcode = opcode;
820 cmd->index = hdev->id;
821
Andre Guedes12b94562012-06-07 19:05:45 -0300822 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200823 if (!cmd->param) {
824 kfree(cmd);
825 return NULL;
826 }
827
828 if (data)
829 memcpy(cmd->param, data, len);
830
831 cmd->sk = sk;
832 sock_hold(sk);
833
834 list_add(&cmd->list, &hdev->mgmt_pending);
835
836 return cmd;
837}
838
839static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300840 void (*cb)(struct pending_cmd *cmd,
841 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300842 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200843{
Andre Guedesa3d09352013-02-01 11:21:30 -0300844 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200845
Andre Guedesa3d09352013-02-01 11:21:30 -0300846 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200847 if (opcode > 0 && cmd->opcode != opcode)
848 continue;
849
850 cb(cmd, data);
851 }
852}
853
854static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
855{
856 struct pending_cmd *cmd;
857
858 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
859 if (cmd->opcode == opcode)
860 return cmd;
861 }
862
863 return NULL;
864}
865
866static void mgmt_pending_remove(struct pending_cmd *cmd)
867{
868 list_del(&cmd->list);
869 mgmt_pending_free(cmd);
870}
871
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200872static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200873{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200874 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200875
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200876 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300877 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200878}
879
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200880static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300881 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200882{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300883 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200884 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200885 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200886
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200887 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200888
Johan Hedberga7e80f22013-01-09 16:05:19 +0200889 if (cp->val != 0x00 && cp->val != 0x01)
890 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
891 MGMT_STATUS_INVALID_PARAMS);
892
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300893 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200894
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300895 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
896 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
897 MGMT_STATUS_BUSY);
898 goto failed;
899 }
900
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100901 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
902 cancel_delayed_work(&hdev->power_off);
903
904 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200905 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
906 data, len);
907 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100908 goto failed;
909 }
910 }
911
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200912 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200913 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200914 goto failed;
915 }
916
Johan Hedberg03811012010-12-08 00:21:06 +0200917 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
918 if (!cmd) {
919 err = -ENOMEM;
920 goto failed;
921 }
922
923 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200924 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200925 else
Johan Hedberg19202572013-01-14 22:33:51 +0200926 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200927
928 err = 0;
929
930failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300931 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200932 return err;
933}
934
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300935static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
936 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200937{
938 struct sk_buff *skb;
939 struct mgmt_hdr *hdr;
940
Andre Guedes790eff42012-06-07 19:05:46 -0300941 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200942 if (!skb)
943 return -ENOMEM;
944
945 hdr = (void *) skb_put(skb, sizeof(*hdr));
946 hdr->opcode = cpu_to_le16(event);
947 if (hdev)
948 hdr->index = cpu_to_le16(hdev->id);
949 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530950 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200951 hdr->len = cpu_to_le16(data_len);
952
953 if (data)
954 memcpy(skb_put(skb, data_len), data, data_len);
955
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100956 /* Time stamp */
957 __net_timestamp(skb);
958
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200959 hci_send_to_control(skb, skip_sk);
960 kfree_skb(skb);
961
962 return 0;
963}
964
965static int new_settings(struct hci_dev *hdev, struct sock *skip)
966{
967 __le32 ev;
968
969 ev = cpu_to_le32(get_current_settings(hdev));
970
971 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
972}
973
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300974struct cmd_lookup {
975 struct sock *sk;
976 struct hci_dev *hdev;
977 u8 mgmt_status;
978};
979
980static void settings_rsp(struct pending_cmd *cmd, void *data)
981{
982 struct cmd_lookup *match = data;
983
984 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
985
986 list_del(&cmd->list);
987
988 if (match->sk == NULL) {
989 match->sk = cmd->sk;
990 sock_hold(match->sk);
991 }
992
993 mgmt_pending_free(cmd);
994}
995
996static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
997{
998 u8 *status = data;
999
1000 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1001 mgmt_pending_remove(cmd);
1002}
1003
Johan Hedberge6fe7982013-10-02 15:45:22 +03001004static u8 mgmt_bredr_support(struct hci_dev *hdev)
1005{
1006 if (!lmp_bredr_capable(hdev))
1007 return MGMT_STATUS_NOT_SUPPORTED;
1008 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1009 return MGMT_STATUS_REJECTED;
1010 else
1011 return MGMT_STATUS_SUCCESS;
1012}
1013
1014static u8 mgmt_le_support(struct hci_dev *hdev)
1015{
1016 if (!lmp_le_capable(hdev))
1017 return MGMT_STATUS_NOT_SUPPORTED;
1018 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1019 return MGMT_STATUS_REJECTED;
1020 else
1021 return MGMT_STATUS_SUCCESS;
1022}
1023
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001024static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1025{
1026 struct pending_cmd *cmd;
1027 struct mgmt_mode *cp;
1028 bool changed;
1029
1030 BT_DBG("status 0x%02x", status);
1031
1032 hci_dev_lock(hdev);
1033
1034 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1035 if (!cmd)
1036 goto unlock;
1037
1038 if (status) {
1039 u8 mgmt_err = mgmt_status(status);
1040 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1041 goto remove_cmd;
1042 }
1043
1044 cp = cmd->param;
1045 if (cp->val)
1046 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1047 &hdev->dev_flags);
1048 else
1049 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1050 &hdev->dev_flags);
1051
1052 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1053
1054 if (changed)
1055 new_settings(hdev, cmd->sk);
1056
1057remove_cmd:
1058 mgmt_pending_remove(cmd);
1059
1060unlock:
1061 hci_dev_unlock(hdev);
1062}
1063
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001064static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001065 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001066{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001067 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001068 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001069 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001070 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001071 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001072 int err;
1073
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001074 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001075
Johan Hedberge6fe7982013-10-02 15:45:22 +03001076 status = mgmt_bredr_support(hdev);
1077 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001078 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001079 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001080
Johan Hedberga7e80f22013-01-09 16:05:19 +02001081 if (cp->val != 0x00 && cp->val != 0x01)
1082 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1083 MGMT_STATUS_INVALID_PARAMS);
1084
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001085 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +01001086 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001087 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001088 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001089
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001090 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001091
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001092 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001093 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001094 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001095 goto failed;
1096 }
1097
1098 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001099 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001100 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001101 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001102 goto failed;
1103 }
1104
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001105 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001106 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001107 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001108 goto failed;
1109 }
1110
1111 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001112 bool changed = false;
1113
1114 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1115 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1116 changed = true;
1117 }
1118
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001119 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001120 if (err < 0)
1121 goto failed;
1122
1123 if (changed)
1124 err = new_settings(hdev, sk);
1125
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001126 goto failed;
1127 }
1128
1129 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +01001130 if (hdev->discov_timeout > 0) {
1131 cancel_delayed_work(&hdev->discov_off);
1132 hdev->discov_timeout = 0;
1133 }
1134
1135 if (cp->val && timeout > 0) {
1136 hdev->discov_timeout = timeout;
1137 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1138 msecs_to_jiffies(hdev->discov_timeout * 1000));
1139 }
1140
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001141 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001142 goto failed;
1143 }
1144
1145 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1146 if (!cmd) {
1147 err = -ENOMEM;
1148 goto failed;
1149 }
1150
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001151 hci_req_init(&req, hdev);
1152
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001153 scan = SCAN_PAGE;
1154
1155 if (cp->val)
1156 scan |= SCAN_INQUIRY;
1157 else
1158 cancel_delayed_work(&hdev->discov_off);
1159
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001160 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1161
1162 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001163 if (err < 0)
1164 mgmt_pending_remove(cmd);
1165
1166 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001167 hdev->discov_timeout = timeout;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001168
1169failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001170 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001171 return err;
1172}
1173
Johan Hedberg406d7802013-03-15 17:07:09 -05001174static void write_fast_connectable(struct hci_request *req, bool enable)
1175{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001176 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001177 struct hci_cp_write_page_scan_activity acp;
1178 u8 type;
1179
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001180 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1181 return;
1182
Johan Hedberg406d7802013-03-15 17:07:09 -05001183 if (enable) {
1184 type = PAGE_SCAN_TYPE_INTERLACED;
1185
1186 /* 160 msec page scan interval */
1187 acp.interval = __constant_cpu_to_le16(0x0100);
1188 } else {
1189 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1190
1191 /* default 1.28 sec page scan */
1192 acp.interval = __constant_cpu_to_le16(0x0800);
1193 }
1194
1195 acp.window = __constant_cpu_to_le16(0x0012);
1196
Johan Hedbergbd98b992013-03-15 17:07:13 -05001197 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1198 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1199 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1200 sizeof(acp), &acp);
1201
1202 if (hdev->page_scan_type != type)
1203 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001204}
1205
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001206static u8 get_adv_type(struct hci_dev *hdev)
1207{
1208 struct pending_cmd *cmd;
1209 bool connectable;
1210
1211 /* If there's a pending mgmt command the flag will not yet have
1212 * it's final value, so check for this first.
1213 */
1214 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1215 if (cmd) {
1216 struct mgmt_mode *cp = cmd->param;
1217 connectable = !!cp->val;
1218 } else {
1219 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1220 }
1221
1222 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1223}
1224
Johan Hedberg95c66e72013-10-14 16:20:06 +03001225static void enable_advertising(struct hci_request *req)
1226{
1227 struct hci_dev *hdev = req->hdev;
1228 struct hci_cp_le_set_adv_param cp;
1229 u8 enable = 0x01;
1230
1231 memset(&cp, 0, sizeof(cp));
1232 cp.min_interval = __constant_cpu_to_le16(0x0800);
1233 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001234 cp.type = get_adv_type(hdev);
Johan Hedberg95c66e72013-10-14 16:20:06 +03001235 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1236 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1237 else
1238 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1239 cp.channel_map = 0x07;
1240
1241 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1242
1243 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1244}
1245
1246static void disable_advertising(struct hci_request *req)
1247{
1248 u8 enable = 0x00;
1249
1250 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1251}
1252
Johan Hedberg2b76f452013-03-15 17:07:04 -05001253static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1254{
1255 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001256 struct mgmt_mode *cp;
1257 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001258
1259 BT_DBG("status 0x%02x", status);
1260
1261 hci_dev_lock(hdev);
1262
1263 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1264 if (!cmd)
1265 goto unlock;
1266
Johan Hedberg37438c12013-10-14 16:20:05 +03001267 if (status) {
1268 u8 mgmt_err = mgmt_status(status);
1269 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1270 goto remove_cmd;
1271 }
1272
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001273 cp = cmd->param;
1274 if (cp->val)
1275 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1276 else
1277 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1278
Johan Hedberg2b76f452013-03-15 17:07:04 -05001279 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1280
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001281 if (changed)
1282 new_settings(hdev, cmd->sk);
1283
Johan Hedberg37438c12013-10-14 16:20:05 +03001284remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001285 mgmt_pending_remove(cmd);
1286
1287unlock:
1288 hci_dev_unlock(hdev);
1289}
1290
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001291static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001292 u16 len)
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001293{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001294 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001295 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001296 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001297 u8 scan;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001298 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001299
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001300 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001301
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001302 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1303 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001304 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001305 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001306
Johan Hedberga7e80f22013-01-09 16:05:19 +02001307 if (cp->val != 0x00 && cp->val != 0x01)
1308 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1309 MGMT_STATUS_INVALID_PARAMS);
1310
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001311 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001312
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001313 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001314 bool changed = false;
1315
1316 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1317 changed = true;
1318
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001319 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001320 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001321 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001322 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1323 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1324 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001325
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001326 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001327 if (err < 0)
1328 goto failed;
1329
1330 if (changed)
1331 err = new_settings(hdev, sk);
1332
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001333 goto failed;
1334 }
1335
1336 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001337 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001338 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001339 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001340 goto failed;
1341 }
1342
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001343 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1344 if (!cmd) {
1345 err = -ENOMEM;
1346 goto failed;
1347 }
1348
Johan Hedberg2b76f452013-03-15 17:07:04 -05001349 hci_req_init(&req, hdev);
1350
Johan Hedberg9b742462013-10-14 16:20:03 +03001351 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) &&
1352 cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001353 if (cp->val) {
1354 scan = SCAN_PAGE;
1355 } else {
1356 scan = 0;
1357
1358 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001359 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001360 cancel_delayed_work(&hdev->discov_off);
1361 }
1362
1363 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1364 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001365
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001366 /* If we're going from non-connectable to connectable or
1367 * vice-versa when fast connectable is enabled ensure that fast
1368 * connectable gets disabled. write_fast_connectable won't do
1369 * anything if the page scan parameters are already what they
1370 * should be.
1371 */
1372 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001373 write_fast_connectable(&req, false);
1374
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001375 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1376 hci_conn_num(hdev, LE_LINK) == 0) {
1377 disable_advertising(&req);
1378 enable_advertising(&req);
1379 }
1380
Johan Hedberg2b76f452013-03-15 17:07:04 -05001381 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001382 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001383 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001384 if (err == -ENODATA)
1385 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE,
1386 hdev);
1387 goto failed;
1388 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001389
1390failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001391 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001392 return err;
1393}
1394
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001395static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001396 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001397{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001398 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001399 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001400 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001401
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001402 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001403
Johan Hedberga7e80f22013-01-09 16:05:19 +02001404 if (cp->val != 0x00 && cp->val != 0x01)
1405 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1406 MGMT_STATUS_INVALID_PARAMS);
1407
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001408 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001409
1410 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001411 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001412 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001413 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001414
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001415 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001416 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001417 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001418
Marcel Holtmann55594352013-10-06 16:11:57 -07001419 if (changed)
1420 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001421
Marcel Holtmann55594352013-10-06 16:11:57 -07001422unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001423 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001424 return err;
1425}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001426
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001427static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1428 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001429{
1430 struct mgmt_mode *cp = data;
1431 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001432 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001433 int err;
1434
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001435 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001436
Johan Hedberge6fe7982013-10-02 15:45:22 +03001437 status = mgmt_bredr_support(hdev);
1438 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001439 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001440 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001441
Johan Hedberga7e80f22013-01-09 16:05:19 +02001442 if (cp->val != 0x00 && cp->val != 0x01)
1443 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1444 MGMT_STATUS_INVALID_PARAMS);
1445
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001446 hci_dev_lock(hdev);
1447
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001448 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001449 bool changed = false;
1450
1451 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001452 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001453 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1454 changed = true;
1455 }
1456
1457 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1458 if (err < 0)
1459 goto failed;
1460
1461 if (changed)
1462 err = new_settings(hdev, sk);
1463
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001464 goto failed;
1465 }
1466
1467 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001468 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001469 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001470 goto failed;
1471 }
1472
1473 val = !!cp->val;
1474
1475 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1476 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1477 goto failed;
1478 }
1479
1480 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1481 if (!cmd) {
1482 err = -ENOMEM;
1483 goto failed;
1484 }
1485
1486 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1487 if (err < 0) {
1488 mgmt_pending_remove(cmd);
1489 goto failed;
1490 }
1491
1492failed:
1493 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001494 return err;
1495}
1496
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001497static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001498{
1499 struct mgmt_mode *cp = data;
1500 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001501 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001502 int err;
1503
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001504 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001505
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001506 status = mgmt_bredr_support(hdev);
1507 if (status)
1508 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1509
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001510 if (!lmp_ssp_capable(hdev))
1511 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1512 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001513
Johan Hedberga7e80f22013-01-09 16:05:19 +02001514 if (cp->val != 0x00 && cp->val != 0x01)
1515 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1516 MGMT_STATUS_INVALID_PARAMS);
1517
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001518 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001519
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001520 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001521 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001522
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001523 if (cp->val) {
1524 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1525 &hdev->dev_flags);
1526 } else {
1527 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1528 &hdev->dev_flags);
1529 if (!changed)
1530 changed = test_and_clear_bit(HCI_HS_ENABLED,
1531 &hdev->dev_flags);
1532 else
1533 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001534 }
1535
1536 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1537 if (err < 0)
1538 goto failed;
1539
1540 if (changed)
1541 err = new_settings(hdev, sk);
1542
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001543 goto failed;
1544 }
1545
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001546 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1547 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001548 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1549 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001550 goto failed;
1551 }
1552
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001553 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001554 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1555 goto failed;
1556 }
1557
1558 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1559 if (!cmd) {
1560 err = -ENOMEM;
1561 goto failed;
1562 }
1563
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001564 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001565 if (err < 0) {
1566 mgmt_pending_remove(cmd);
1567 goto failed;
1568 }
1569
1570failed:
1571 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001572 return err;
1573}
1574
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001575static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001576{
1577 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001578 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001579 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001580 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001581
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001582 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001583
Johan Hedberge6fe7982013-10-02 15:45:22 +03001584 status = mgmt_bredr_support(hdev);
1585 if (status)
1586 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001587
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001588 if (!lmp_ssp_capable(hdev))
1589 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1590 MGMT_STATUS_NOT_SUPPORTED);
1591
1592 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1593 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1594 MGMT_STATUS_REJECTED);
1595
Johan Hedberga7e80f22013-01-09 16:05:19 +02001596 if (cp->val != 0x00 && cp->val != 0x01)
1597 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1598 MGMT_STATUS_INVALID_PARAMS);
1599
Marcel Holtmannee392692013-10-01 22:59:23 -07001600 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001601
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001602 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001603 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001604 } else {
1605 if (hdev_is_powered(hdev)) {
1606 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1607 MGMT_STATUS_REJECTED);
1608 goto unlock;
1609 }
1610
Marcel Holtmannee392692013-10-01 22:59:23 -07001611 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001612 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001613
1614 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1615 if (err < 0)
1616 goto unlock;
1617
1618 if (changed)
1619 err = new_settings(hdev, sk);
1620
1621unlock:
1622 hci_dev_unlock(hdev);
1623 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001624}
1625
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001626static void le_enable_complete(struct hci_dev *hdev, u8 status)
1627{
1628 struct cmd_lookup match = { NULL, hdev };
1629
1630 if (status) {
1631 u8 mgmt_err = mgmt_status(status);
1632
1633 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1634 &mgmt_err);
1635 return;
1636 }
1637
1638 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1639
1640 new_settings(hdev, match.sk);
1641
1642 if (match.sk)
1643 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001644
1645 /* Make sure the controller has a good default for
1646 * advertising data. Restrict the update to when LE
1647 * has actually been enabled. During power on, the
1648 * update in powered_update_hci will take care of it.
1649 */
1650 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1651 struct hci_request req;
1652
1653 hci_dev_lock(hdev);
1654
1655 hci_req_init(&req, hdev);
1656 update_ad(&req);
1657 hci_req_run(&req, NULL);
1658
1659 hci_dev_unlock(hdev);
1660 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001661}
1662
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001663static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001664{
1665 struct mgmt_mode *cp = data;
1666 struct hci_cp_write_le_host_supported hci_cp;
1667 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001668 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001669 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001670 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001671
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001672 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001673
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001674 if (!lmp_le_capable(hdev))
1675 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1676 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001677
Johan Hedberga7e80f22013-01-09 16:05:19 +02001678 if (cp->val != 0x00 && cp->val != 0x01)
1679 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1680 MGMT_STATUS_INVALID_PARAMS);
1681
Johan Hedbergc73eee92013-04-19 18:35:21 +03001682 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001683 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001684 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1685 MGMT_STATUS_REJECTED);
1686
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001687 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001688
1689 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001690 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001691
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001692 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001693 bool changed = false;
1694
1695 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1696 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1697 changed = true;
1698 }
1699
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001700 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1701 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001702 changed = true;
1703 }
1704
Johan Hedberg06199cf2012-02-22 16:37:11 +02001705 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1706 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001707 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001708
1709 if (changed)
1710 err = new_settings(hdev, sk);
1711
Johan Hedberg1de028c2012-02-29 19:55:35 -08001712 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001713 }
1714
Johan Hedberg4375f102013-09-25 13:26:10 +03001715 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1716 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001717 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001718 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001719 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001720 }
1721
1722 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1723 if (!cmd) {
1724 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001725 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001726 }
1727
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001728 hci_req_init(&req, hdev);
1729
Johan Hedberg06199cf2012-02-22 16:37:11 +02001730 memset(&hci_cp, 0, sizeof(hci_cp));
1731
1732 if (val) {
1733 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001734 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001735 } else {
1736 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1737 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001738 }
1739
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001740 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1741 &hci_cp);
1742
1743 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301744 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001745 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001746
Johan Hedberg1de028c2012-02-29 19:55:35 -08001747unlock:
1748 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001749 return err;
1750}
1751
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001752/* This is a helper function to test for pending mgmt commands that can
1753 * cause CoD or EIR HCI commands. We can only allow one such pending
1754 * mgmt command at a time since otherwise we cannot easily track what
1755 * the current values are, will be, and based on that calculate if a new
1756 * HCI command needs to be sent and if yes with what value.
1757 */
1758static bool pending_eir_or_class(struct hci_dev *hdev)
1759{
1760 struct pending_cmd *cmd;
1761
1762 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1763 switch (cmd->opcode) {
1764 case MGMT_OP_ADD_UUID:
1765 case MGMT_OP_REMOVE_UUID:
1766 case MGMT_OP_SET_DEV_CLASS:
1767 case MGMT_OP_SET_POWERED:
1768 return true;
1769 }
1770 }
1771
1772 return false;
1773}
1774
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001775static const u8 bluetooth_base_uuid[] = {
1776 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1777 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1778};
1779
1780static u8 get_uuid_size(const u8 *uuid)
1781{
1782 u32 val;
1783
1784 if (memcmp(uuid, bluetooth_base_uuid, 12))
1785 return 128;
1786
1787 val = get_unaligned_le32(&uuid[12]);
1788 if (val > 0xffff)
1789 return 32;
1790
1791 return 16;
1792}
1793
Johan Hedberg92da6092013-03-15 17:06:55 -05001794static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1795{
1796 struct pending_cmd *cmd;
1797
1798 hci_dev_lock(hdev);
1799
1800 cmd = mgmt_pending_find(mgmt_op, hdev);
1801 if (!cmd)
1802 goto unlock;
1803
1804 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1805 hdev->dev_class, 3);
1806
1807 mgmt_pending_remove(cmd);
1808
1809unlock:
1810 hci_dev_unlock(hdev);
1811}
1812
1813static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1814{
1815 BT_DBG("status 0x%02x", status);
1816
1817 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1818}
1819
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001820static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001821{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001822 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001823 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001824 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001825 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001826 int err;
1827
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001828 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001829
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001830 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001831
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001832 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001833 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001834 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001835 goto failed;
1836 }
1837
Andre Guedes92c4c202012-06-07 19:05:44 -03001838 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001839 if (!uuid) {
1840 err = -ENOMEM;
1841 goto failed;
1842 }
1843
1844 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001845 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001846 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001847
Johan Hedbergde66aa62013-01-27 00:31:27 +02001848 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001849
Johan Hedberg890ea892013-03-15 17:06:52 -05001850 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001851
Johan Hedberg890ea892013-03-15 17:06:52 -05001852 update_class(&req);
1853 update_eir(&req);
1854
Johan Hedberg92da6092013-03-15 17:06:55 -05001855 err = hci_req_run(&req, add_uuid_complete);
1856 if (err < 0) {
1857 if (err != -ENODATA)
1858 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001859
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001860 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001861 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001862 goto failed;
1863 }
1864
1865 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001866 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001867 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001868 goto failed;
1869 }
1870
1871 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001872
1873failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001874 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001875 return err;
1876}
1877
Johan Hedberg24b78d02012-02-23 23:24:30 +02001878static bool enable_service_cache(struct hci_dev *hdev)
1879{
1880 if (!hdev_is_powered(hdev))
1881 return false;
1882
1883 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001884 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1885 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001886 return true;
1887 }
1888
1889 return false;
1890}
1891
Johan Hedberg92da6092013-03-15 17:06:55 -05001892static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1893{
1894 BT_DBG("status 0x%02x", status);
1895
1896 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1897}
1898
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001899static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001900 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001901{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001902 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001903 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001904 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001905 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 -05001906 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001907 int err, found;
1908
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001909 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001910
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001911 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001912
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001913 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001914 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001915 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001916 goto unlock;
1917 }
1918
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001919 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1920 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001921
Johan Hedberg24b78d02012-02-23 23:24:30 +02001922 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001923 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001924 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001925 goto unlock;
1926 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001927
Johan Hedberg9246a862012-02-23 21:33:16 +02001928 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001929 }
1930
1931 found = 0;
1932
Johan Hedberg056341c2013-01-27 00:31:30 +02001933 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001934 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1935 continue;
1936
1937 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001938 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001939 found++;
1940 }
1941
1942 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001943 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001944 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001945 goto unlock;
1946 }
1947
Johan Hedberg9246a862012-02-23 21:33:16 +02001948update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001949 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001950
Johan Hedberg890ea892013-03-15 17:06:52 -05001951 update_class(&req);
1952 update_eir(&req);
1953
Johan Hedberg92da6092013-03-15 17:06:55 -05001954 err = hci_req_run(&req, remove_uuid_complete);
1955 if (err < 0) {
1956 if (err != -ENODATA)
1957 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001958
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001959 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001960 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001961 goto unlock;
1962 }
1963
1964 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001965 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001966 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001967 goto unlock;
1968 }
1969
1970 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001971
1972unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001973 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001974 return err;
1975}
1976
Johan Hedberg92da6092013-03-15 17:06:55 -05001977static void set_class_complete(struct hci_dev *hdev, u8 status)
1978{
1979 BT_DBG("status 0x%02x", status);
1980
1981 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1982}
1983
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001984static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001985 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001986{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001987 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001988 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001989 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001990 int err;
1991
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001992 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001993
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001994 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001995 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1996 MGMT_STATUS_NOT_SUPPORTED);
1997
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001998 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001999
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002000 if (pending_eir_or_class(hdev)) {
2001 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2002 MGMT_STATUS_BUSY);
2003 goto unlock;
2004 }
2005
2006 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2007 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2008 MGMT_STATUS_INVALID_PARAMS);
2009 goto unlock;
2010 }
2011
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002012 hdev->major_class = cp->major;
2013 hdev->minor_class = cp->minor;
2014
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002015 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002016 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002017 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002018 goto unlock;
2019 }
2020
Johan Hedberg890ea892013-03-15 17:06:52 -05002021 hci_req_init(&req, hdev);
2022
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002023 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002024 hci_dev_unlock(hdev);
2025 cancel_delayed_work_sync(&hdev->service_cache);
2026 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002027 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002028 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002029
Johan Hedberg890ea892013-03-15 17:06:52 -05002030 update_class(&req);
2031
Johan Hedberg92da6092013-03-15 17:06:55 -05002032 err = hci_req_run(&req, set_class_complete);
2033 if (err < 0) {
2034 if (err != -ENODATA)
2035 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002036
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002037 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002038 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002039 goto unlock;
2040 }
2041
2042 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002043 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002044 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002045 goto unlock;
2046 }
2047
2048 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002049
Johan Hedbergb5235a62012-02-21 14:32:24 +02002050unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002051 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002052 return err;
2053}
2054
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002055static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002056 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002057{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002058 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002059 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002060 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002061
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002062 BT_DBG("request for %s", hdev->name);
2063
2064 if (!lmp_bredr_capable(hdev))
2065 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2066 MGMT_STATUS_NOT_SUPPORTED);
2067
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002068 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002069
Johan Hedberg86742e12011-11-07 23:13:38 +02002070 expected_len = sizeof(*cp) + key_count *
2071 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002072 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002073 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002074 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002075 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002076 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002077 }
2078
Johan Hedberg4ae14302013-01-20 14:27:13 +02002079 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2080 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2081 MGMT_STATUS_INVALID_PARAMS);
2082
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002083 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002084 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002085
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002086 for (i = 0; i < key_count; i++) {
2087 struct mgmt_link_key_info *key = &cp->keys[i];
2088
2089 if (key->addr.type != BDADDR_BREDR)
2090 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2091 MGMT_STATUS_INVALID_PARAMS);
2092 }
2093
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002094 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002095
2096 hci_link_keys_clear(hdev);
2097
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002098 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002099 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002100 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002101 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002102
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002103 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002104 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002105
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002106 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002107 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002108 }
2109
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002110 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002111
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002112 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002113
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002114 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002115}
2116
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002117static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002118 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002119{
2120 struct mgmt_ev_device_unpaired ev;
2121
2122 bacpy(&ev.addr.bdaddr, bdaddr);
2123 ev.addr.type = addr_type;
2124
2125 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002126 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002127}
2128
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002129static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002130 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002131{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002132 struct mgmt_cp_unpair_device *cp = data;
2133 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002134 struct hci_cp_disconnect dc;
2135 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002136 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002137 int err;
2138
Johan Hedberga8a1d192011-11-10 15:54:38 +02002139 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002140 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2141 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002142
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002143 if (!bdaddr_type_is_valid(cp->addr.type))
2144 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2145 MGMT_STATUS_INVALID_PARAMS,
2146 &rp, sizeof(rp));
2147
Johan Hedberg118da702013-01-20 14:27:20 +02002148 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2149 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2150 MGMT_STATUS_INVALID_PARAMS,
2151 &rp, sizeof(rp));
2152
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002153 hci_dev_lock(hdev);
2154
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002155 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002156 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002157 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002158 goto unlock;
2159 }
2160
Andre Guedes591f47f2012-04-24 21:02:49 -03002161 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02002162 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
2163 else
2164 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002165
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002166 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002167 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002168 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002169 goto unlock;
2170 }
2171
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002172 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002173 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002174 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002175 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002176 else
2177 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002178 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002179 } else {
2180 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002181 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002182
Johan Hedberga8a1d192011-11-10 15:54:38 +02002183 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002184 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002185 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002186 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002187 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002188 }
2189
Johan Hedberg124f6e32012-02-09 13:50:12 +02002190 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002191 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002192 if (!cmd) {
2193 err = -ENOMEM;
2194 goto unlock;
2195 }
2196
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002197 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002198 dc.reason = 0x13; /* Remote User Terminated Connection */
2199 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2200 if (err < 0)
2201 mgmt_pending_remove(cmd);
2202
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002203unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002204 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002205 return err;
2206}
2207
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002208static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002209 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002210{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002211 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002212 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002213 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002214 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002215 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002216 int err;
2217
2218 BT_DBG("");
2219
Johan Hedberg06a63b12013-01-20 14:27:21 +02002220 memset(&rp, 0, sizeof(rp));
2221 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2222 rp.addr.type = cp->addr.type;
2223
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002224 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002225 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2226 MGMT_STATUS_INVALID_PARAMS,
2227 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002228
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002229 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002230
2231 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002232 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2233 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002234 goto failed;
2235 }
2236
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002237 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002238 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2239 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002240 goto failed;
2241 }
2242
Andre Guedes591f47f2012-04-24 21:02:49 -03002243 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002244 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2245 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002246 else
2247 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002248
Vishal Agarwalf9607272012-06-13 05:32:43 +05302249 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002250 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2251 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002252 goto failed;
2253 }
2254
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002255 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002256 if (!cmd) {
2257 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002258 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002259 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002260
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002261 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002262 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002263
2264 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2265 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002266 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002267
2268failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002269 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002270 return err;
2271}
2272
Andre Guedes57c14772012-04-24 21:02:50 -03002273static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002274{
2275 switch (link_type) {
2276 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002277 switch (addr_type) {
2278 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002279 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002280
Johan Hedberg48264f02011-11-09 13:58:58 +02002281 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002282 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002283 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002284 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002285
Johan Hedberg4c659c32011-11-07 23:13:39 +02002286 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002287 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002288 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002289 }
2290}
2291
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002292static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2293 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002294{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002295 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002296 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002297 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002298 int err;
2299 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002300
2301 BT_DBG("");
2302
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002303 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002304
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002305 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002306 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002307 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002308 goto unlock;
2309 }
2310
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002311 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002312 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2313 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002314 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002315 }
2316
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002317 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002318 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002319 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002320 err = -ENOMEM;
2321 goto unlock;
2322 }
2323
Johan Hedberg2784eb42011-01-21 13:56:35 +02002324 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002325 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002326 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2327 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002328 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002329 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002330 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002331 continue;
2332 i++;
2333 }
2334
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002335 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002336
Johan Hedberg4c659c32011-11-07 23:13:39 +02002337 /* Recalculate length in case of filtered SCO connections, etc */
2338 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002339
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002340 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002341 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002342
Johan Hedberga38528f2011-01-22 06:46:43 +02002343 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002344
2345unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002346 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002347 return err;
2348}
2349
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002350static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002351 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002352{
2353 struct pending_cmd *cmd;
2354 int err;
2355
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002356 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002357 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002358 if (!cmd)
2359 return -ENOMEM;
2360
Johan Hedbergd8457692012-02-17 14:24:57 +02002361 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002362 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002363 if (err < 0)
2364 mgmt_pending_remove(cmd);
2365
2366 return err;
2367}
2368
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002369static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002370 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002371{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002372 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002373 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002374 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002375 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002376 int err;
2377
2378 BT_DBG("");
2379
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002380 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002381
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002382 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002383 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002384 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002385 goto failed;
2386 }
2387
Johan Hedbergd8457692012-02-17 14:24:57 +02002388 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002389 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002390 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002391 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002392 goto failed;
2393 }
2394
2395 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002396 struct mgmt_cp_pin_code_neg_reply ncp;
2397
2398 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002399
2400 BT_ERR("PIN code is not 16 bytes long");
2401
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002402 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002403 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002404 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002405 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002406
2407 goto failed;
2408 }
2409
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002410 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002411 if (!cmd) {
2412 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002413 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002414 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002415
Johan Hedbergd8457692012-02-17 14:24:57 +02002416 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002417 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002418 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002419
2420 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2421 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002422 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002423
2424failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002425 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002426 return err;
2427}
2428
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002429static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2430 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002431{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002432 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002433
2434 BT_DBG("");
2435
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002436 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002437
2438 hdev->io_capability = cp->io_capability;
2439
2440 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002441 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002442
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002443 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002444
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002445 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2446 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002447}
2448
Gustavo Padovan6039aa732012-05-23 04:04:18 -03002449static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002450{
2451 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002452 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002453
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002454 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002455 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2456 continue;
2457
Johan Hedberge9a416b2011-02-19 12:05:56 -03002458 if (cmd->user_data != conn)
2459 continue;
2460
2461 return cmd;
2462 }
2463
2464 return NULL;
2465}
2466
2467static void pairing_complete(struct pending_cmd *cmd, u8 status)
2468{
2469 struct mgmt_rp_pair_device rp;
2470 struct hci_conn *conn = cmd->user_data;
2471
Johan Hedbergba4e5642011-11-11 00:07:34 +02002472 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002473 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002474
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002475 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002476 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002477
2478 /* So we don't get further callbacks for this connection */
2479 conn->connect_cfm_cb = NULL;
2480 conn->security_cfm_cb = NULL;
2481 conn->disconn_cfm_cb = NULL;
2482
David Herrmann76a68ba2013-04-06 20:28:37 +02002483 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002484
Johan Hedberga664b5b2011-02-19 12:06:02 -03002485 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002486}
2487
2488static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2489{
2490 struct pending_cmd *cmd;
2491
2492 BT_DBG("status %u", status);
2493
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002494 cmd = find_pairing(conn);
2495 if (!cmd)
2496 BT_DBG("Unable to find a pending command");
2497 else
Johan Hedberge2113262012-02-18 15:20:03 +02002498 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002499}
2500
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302501static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2502{
2503 struct pending_cmd *cmd;
2504
2505 BT_DBG("status %u", status);
2506
2507 if (!status)
2508 return;
2509
2510 cmd = find_pairing(conn);
2511 if (!cmd)
2512 BT_DBG("Unable to find a pending command");
2513 else
2514 pairing_complete(cmd, mgmt_status(status));
2515}
2516
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002517static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002518 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002519{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002520 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002521 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002522 struct pending_cmd *cmd;
2523 u8 sec_level, auth_type;
2524 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002525 int err;
2526
2527 BT_DBG("");
2528
Szymon Jancf950a30e2013-01-18 12:48:07 +01002529 memset(&rp, 0, sizeof(rp));
2530 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2531 rp.addr.type = cp->addr.type;
2532
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002533 if (!bdaddr_type_is_valid(cp->addr.type))
2534 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2535 MGMT_STATUS_INVALID_PARAMS,
2536 &rp, sizeof(rp));
2537
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002538 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002539
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002540 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002541 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2542 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002543 goto unlock;
2544 }
2545
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002546 sec_level = BT_SECURITY_MEDIUM;
2547 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002548 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002549 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002550 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002551
Andre Guedes591f47f2012-04-24 21:02:49 -03002552 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002553 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2554 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002555 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002556 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2557 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002558
Ville Tervo30e76272011-02-22 16:10:53 -03002559 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002560 int status;
2561
2562 if (PTR_ERR(conn) == -EBUSY)
2563 status = MGMT_STATUS_BUSY;
2564 else
2565 status = MGMT_STATUS_CONNECT_FAILED;
2566
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002567 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002568 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002569 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002570 goto unlock;
2571 }
2572
2573 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002574 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002575 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002576 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002577 goto unlock;
2578 }
2579
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002580 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002581 if (!cmd) {
2582 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002583 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002584 goto unlock;
2585 }
2586
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002587 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002588 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002589 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302590 else
2591 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002592
Johan Hedberge9a416b2011-02-19 12:05:56 -03002593 conn->security_cfm_cb = pairing_complete_cb;
2594 conn->disconn_cfm_cb = pairing_complete_cb;
2595 conn->io_capability = cp->io_cap;
2596 cmd->user_data = conn;
2597
2598 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002599 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002600 pairing_complete(cmd, 0);
2601
2602 err = 0;
2603
2604unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002605 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002606 return err;
2607}
2608
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002609static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2610 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002611{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002612 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002613 struct pending_cmd *cmd;
2614 struct hci_conn *conn;
2615 int err;
2616
2617 BT_DBG("");
2618
Johan Hedberg28424702012-02-02 04:02:29 +02002619 hci_dev_lock(hdev);
2620
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002621 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002622 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002623 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002624 goto unlock;
2625 }
2626
Johan Hedberg28424702012-02-02 04:02:29 +02002627 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2628 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002629 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002630 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002631 goto unlock;
2632 }
2633
2634 conn = cmd->user_data;
2635
2636 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002637 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002638 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002639 goto unlock;
2640 }
2641
2642 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2643
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002644 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002645 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002646unlock:
2647 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002648 return err;
2649}
2650
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002651static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002652 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002653 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002654{
Johan Hedberga5c29682011-02-19 12:05:57 -03002655 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002656 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002657 int err;
2658
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002659 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002660
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002661 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002662 err = cmd_complete(sk, hdev->id, mgmt_op,
2663 MGMT_STATUS_NOT_POWERED, addr,
2664 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002665 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002666 }
2667
Johan Hedberg1707c602013-03-15 17:07:15 -05002668 if (addr->type == BDADDR_BREDR)
2669 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002670 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002671 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002672
Johan Hedberg272d90d2012-02-09 15:26:12 +02002673 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002674 err = cmd_complete(sk, hdev->id, mgmt_op,
2675 MGMT_STATUS_NOT_CONNECTED, addr,
2676 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002677 goto done;
2678 }
2679
Johan Hedberg1707c602013-03-15 17:07:15 -05002680 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002681 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002682 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002683
Brian Gix5fe57d92011-12-21 16:12:13 -08002684 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002685 err = cmd_complete(sk, hdev->id, mgmt_op,
2686 MGMT_STATUS_SUCCESS, addr,
2687 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002688 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002689 err = cmd_complete(sk, hdev->id, mgmt_op,
2690 MGMT_STATUS_FAILED, addr,
2691 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002692
Brian Gix47c15e22011-11-16 13:53:14 -08002693 goto done;
2694 }
2695
Johan Hedberg1707c602013-03-15 17:07:15 -05002696 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002697 if (!cmd) {
2698 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002699 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002700 }
2701
Brian Gix0df4c182011-11-16 13:53:13 -08002702 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002703 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2704 struct hci_cp_user_passkey_reply cp;
2705
Johan Hedberg1707c602013-03-15 17:07:15 -05002706 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002707 cp.passkey = passkey;
2708 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2709 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002710 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2711 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002712
Johan Hedberga664b5b2011-02-19 12:06:02 -03002713 if (err < 0)
2714 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002715
Brian Gix0df4c182011-11-16 13:53:13 -08002716done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002717 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002718 return err;
2719}
2720
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302721static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2722 void *data, u16 len)
2723{
2724 struct mgmt_cp_pin_code_neg_reply *cp = data;
2725
2726 BT_DBG("");
2727
Johan Hedberg1707c602013-03-15 17:07:15 -05002728 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302729 MGMT_OP_PIN_CODE_NEG_REPLY,
2730 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2731}
2732
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002733static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2734 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002735{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002736 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002737
2738 BT_DBG("");
2739
2740 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002741 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002742 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002743
Johan Hedberg1707c602013-03-15 17:07:15 -05002744 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002745 MGMT_OP_USER_CONFIRM_REPLY,
2746 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002747}
2748
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002749static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002750 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002751{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002752 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002753
2754 BT_DBG("");
2755
Johan Hedberg1707c602013-03-15 17:07:15 -05002756 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002757 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2758 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002759}
2760
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002761static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2762 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002763{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002764 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002765
2766 BT_DBG("");
2767
Johan Hedberg1707c602013-03-15 17:07:15 -05002768 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002769 MGMT_OP_USER_PASSKEY_REPLY,
2770 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002771}
2772
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002773static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002774 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002775{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002776 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002777
2778 BT_DBG("");
2779
Johan Hedberg1707c602013-03-15 17:07:15 -05002780 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002781 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2782 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002783}
2784
Johan Hedberg13928972013-03-15 17:07:00 -05002785static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002786{
Johan Hedberg13928972013-03-15 17:07:00 -05002787 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002788 struct hci_cp_write_local_name cp;
2789
Johan Hedberg13928972013-03-15 17:07:00 -05002790 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002791
Johan Hedberg890ea892013-03-15 17:06:52 -05002792 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002793}
2794
Johan Hedberg13928972013-03-15 17:07:00 -05002795static void set_name_complete(struct hci_dev *hdev, u8 status)
2796{
2797 struct mgmt_cp_set_local_name *cp;
2798 struct pending_cmd *cmd;
2799
2800 BT_DBG("status 0x%02x", status);
2801
2802 hci_dev_lock(hdev);
2803
2804 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2805 if (!cmd)
2806 goto unlock;
2807
2808 cp = cmd->param;
2809
2810 if (status)
2811 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2812 mgmt_status(status));
2813 else
2814 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2815 cp, sizeof(*cp));
2816
2817 mgmt_pending_remove(cmd);
2818
2819unlock:
2820 hci_dev_unlock(hdev);
2821}
2822
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002823static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002824 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002825{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002826 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002827 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002828 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002829 int err;
2830
2831 BT_DBG("");
2832
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002833 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002834
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002835 /* If the old values are the same as the new ones just return a
2836 * direct command complete event.
2837 */
2838 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2839 !memcmp(hdev->short_name, cp->short_name,
2840 sizeof(hdev->short_name))) {
2841 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2842 data, len);
2843 goto failed;
2844 }
2845
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002846 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002847
Johan Hedbergb5235a62012-02-21 14:32:24 +02002848 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002849 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002850
2851 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002852 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002853 if (err < 0)
2854 goto failed;
2855
2856 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002857 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002858
Johan Hedbergb5235a62012-02-21 14:32:24 +02002859 goto failed;
2860 }
2861
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002862 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002863 if (!cmd) {
2864 err = -ENOMEM;
2865 goto failed;
2866 }
2867
Johan Hedberg13928972013-03-15 17:07:00 -05002868 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2869
Johan Hedberg890ea892013-03-15 17:06:52 -05002870 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002871
2872 if (lmp_bredr_capable(hdev)) {
2873 update_name(&req);
2874 update_eir(&req);
2875 }
2876
2877 if (lmp_le_capable(hdev))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002878 update_ad(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05002879
Johan Hedberg13928972013-03-15 17:07:00 -05002880 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002881 if (err < 0)
2882 mgmt_pending_remove(cmd);
2883
2884failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002885 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002886 return err;
2887}
2888
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002889static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002890 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002891{
Szymon Jancc35938b2011-03-22 13:12:21 +01002892 struct pending_cmd *cmd;
2893 int err;
2894
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002895 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002896
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002897 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002898
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002899 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002900 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002901 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002902 goto unlock;
2903 }
2904
Andre Guedes9a1a1992012-07-24 15:03:48 -03002905 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002906 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002907 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002908 goto unlock;
2909 }
2910
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002911 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002912 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002913 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002914 goto unlock;
2915 }
2916
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002917 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002918 if (!cmd) {
2919 err = -ENOMEM;
2920 goto unlock;
2921 }
2922
2923 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2924 if (err < 0)
2925 mgmt_pending_remove(cmd);
2926
2927unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002928 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002929 return err;
2930}
2931
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002932static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002933 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002934{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002935 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002936 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002937 int err;
2938
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002939 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002940
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002941 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002942
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002943 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002944 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002945 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002946 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002947 else
Szymon Janca6785be2012-12-13 15:11:21 +01002948 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002949
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002950 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002951 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002952
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002953 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002954 return err;
2955}
2956
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002957static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002958 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002959{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002960 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002961 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002962 int err;
2963
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002964 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002965
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002966 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002967
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002968 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002969 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002970 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002971 else
Szymon Janca6785be2012-12-13 15:11:21 +01002972 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002973
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002974 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002975 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002976
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002977 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002978 return err;
2979}
2980
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002981static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2982{
2983 struct pending_cmd *cmd;
2984 u8 type;
2985 int err;
2986
2987 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2988
2989 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2990 if (!cmd)
2991 return -ENOENT;
2992
2993 type = hdev->discovery.type;
2994
2995 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2996 &type, sizeof(type));
2997 mgmt_pending_remove(cmd);
2998
2999 return err;
3000}
3001
Andre Guedes7c307722013-04-30 15:29:28 -03003002static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3003{
3004 BT_DBG("status %d", status);
3005
3006 if (status) {
3007 hci_dev_lock(hdev);
3008 mgmt_start_discovery_failed(hdev, status);
3009 hci_dev_unlock(hdev);
3010 return;
3011 }
3012
3013 hci_dev_lock(hdev);
3014 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3015 hci_dev_unlock(hdev);
3016
3017 switch (hdev->discovery.type) {
3018 case DISCOV_TYPE_LE:
3019 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003020 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003021 break;
3022
3023 case DISCOV_TYPE_INTERLEAVED:
3024 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003025 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003026 break;
3027
3028 case DISCOV_TYPE_BREDR:
3029 break;
3030
3031 default:
3032 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3033 }
3034}
3035
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003036static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003037 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003038{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003039 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003040 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003041 struct hci_cp_le_set_scan_param param_cp;
3042 struct hci_cp_le_set_scan_enable enable_cp;
3043 struct hci_cp_inquiry inq_cp;
3044 struct hci_request req;
3045 /* General inquiry access code (GIAC) */
3046 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003047 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003048 int err;
3049
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003050 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003051
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003052 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003053
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003054 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003055 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003056 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003057 goto failed;
3058 }
3059
Andre Guedes642be6c2012-03-21 00:03:37 -03003060 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3061 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3062 MGMT_STATUS_BUSY);
3063 goto failed;
3064 }
3065
Johan Hedbergff9ef572012-01-04 14:23:45 +02003066 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003067 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003068 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003069 goto failed;
3070 }
3071
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003072 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003073 if (!cmd) {
3074 err = -ENOMEM;
3075 goto failed;
3076 }
3077
Andre Guedes4aab14e2012-02-17 20:39:36 -03003078 hdev->discovery.type = cp->type;
3079
Andre Guedes7c307722013-04-30 15:29:28 -03003080 hci_req_init(&req, hdev);
3081
Andre Guedes4aab14e2012-02-17 20:39:36 -03003082 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003083 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003084 status = mgmt_bredr_support(hdev);
3085 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003086 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003087 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003088 mgmt_pending_remove(cmd);
3089 goto failed;
3090 }
3091
Andre Guedes7c307722013-04-30 15:29:28 -03003092 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3093 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3094 MGMT_STATUS_BUSY);
3095 mgmt_pending_remove(cmd);
3096 goto failed;
3097 }
3098
3099 hci_inquiry_cache_flush(hdev);
3100
3101 memset(&inq_cp, 0, sizeof(inq_cp));
3102 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003103 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003104 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003105 break;
3106
3107 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003108 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003109 status = mgmt_le_support(hdev);
3110 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003111 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003112 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003113 mgmt_pending_remove(cmd);
3114 goto failed;
3115 }
3116
Andre Guedes7c307722013-04-30 15:29:28 -03003117 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003118 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003119 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3120 MGMT_STATUS_NOT_SUPPORTED);
3121 mgmt_pending_remove(cmd);
3122 goto failed;
3123 }
3124
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003125 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003126 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3127 MGMT_STATUS_REJECTED);
3128 mgmt_pending_remove(cmd);
3129 goto failed;
3130 }
3131
3132 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3133 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3134 MGMT_STATUS_BUSY);
3135 mgmt_pending_remove(cmd);
3136 goto failed;
3137 }
3138
3139 memset(&param_cp, 0, sizeof(param_cp));
3140 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003141 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3142 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07003143 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
3144 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
3145 else
3146 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03003147 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3148 &param_cp);
3149
3150 memset(&enable_cp, 0, sizeof(enable_cp));
3151 enable_cp.enable = LE_SCAN_ENABLE;
3152 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3153 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3154 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003155 break;
3156
Andre Guedesf39799f2012-02-17 20:39:35 -03003157 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003158 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3159 MGMT_STATUS_INVALID_PARAMS);
3160 mgmt_pending_remove(cmd);
3161 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003162 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003163
Andre Guedes7c307722013-04-30 15:29:28 -03003164 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003165 if (err < 0)
3166 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003167 else
3168 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003169
3170failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003171 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003172 return err;
3173}
3174
Andre Guedes1183fdc2013-04-30 15:29:35 -03003175static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3176{
3177 struct pending_cmd *cmd;
3178 int err;
3179
3180 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3181 if (!cmd)
3182 return -ENOENT;
3183
3184 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3185 &hdev->discovery.type, sizeof(hdev->discovery.type));
3186 mgmt_pending_remove(cmd);
3187
3188 return err;
3189}
3190
Andre Guedes0e05bba2013-04-30 15:29:33 -03003191static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3192{
3193 BT_DBG("status %d", status);
3194
3195 hci_dev_lock(hdev);
3196
3197 if (status) {
3198 mgmt_stop_discovery_failed(hdev, status);
3199 goto unlock;
3200 }
3201
3202 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3203
3204unlock:
3205 hci_dev_unlock(hdev);
3206}
3207
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003208static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003209 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003210{
Johan Hedbergd9306502012-02-20 23:25:18 +02003211 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003212 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003213 struct hci_cp_remote_name_req_cancel cp;
3214 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003215 struct hci_request req;
3216 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003217 int err;
3218
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003219 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003220
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003221 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003222
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003223 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003224 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003225 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3226 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003227 goto unlock;
3228 }
3229
3230 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003231 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003232 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3233 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003234 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003235 }
3236
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003237 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003238 if (!cmd) {
3239 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003240 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003241 }
3242
Andre Guedes0e05bba2013-04-30 15:29:33 -03003243 hci_req_init(&req, hdev);
3244
Andre Guedese0d9727e2012-03-20 15:15:36 -03003245 switch (hdev->discovery.state) {
3246 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003247 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3248 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3249 } else {
3250 cancel_delayed_work(&hdev->le_scan_disable);
3251
3252 memset(&enable_cp, 0, sizeof(enable_cp));
3253 enable_cp.enable = LE_SCAN_DISABLE;
3254 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3255 sizeof(enable_cp), &enable_cp);
3256 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003257
Andre Guedese0d9727e2012-03-20 15:15:36 -03003258 break;
3259
3260 case DISCOVERY_RESOLVING:
3261 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003262 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003263 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003264 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003265 err = cmd_complete(sk, hdev->id,
3266 MGMT_OP_STOP_DISCOVERY, 0,
3267 &mgmt_cp->type,
3268 sizeof(mgmt_cp->type));
3269 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3270 goto unlock;
3271 }
3272
3273 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003274 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3275 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003276
3277 break;
3278
3279 default:
3280 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003281
3282 mgmt_pending_remove(cmd);
3283 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3284 MGMT_STATUS_FAILED, &mgmt_cp->type,
3285 sizeof(mgmt_cp->type));
3286 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003287 }
3288
Andre Guedes0e05bba2013-04-30 15:29:33 -03003289 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003290 if (err < 0)
3291 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003292 else
3293 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003294
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003295unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003296 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003297 return err;
3298}
3299
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003300static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003301 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003302{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003303 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003304 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003305 int err;
3306
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003307 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003308
Johan Hedberg561aafb2012-01-04 13:31:59 +02003309 hci_dev_lock(hdev);
3310
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003311 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003312 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003313 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003314 goto failed;
3315 }
3316
Johan Hedberga198e7b2012-02-17 14:27:06 +02003317 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003318 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003319 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003320 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003321 goto failed;
3322 }
3323
3324 if (cp->name_known) {
3325 e->name_state = NAME_KNOWN;
3326 list_del(&e->list);
3327 } else {
3328 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003329 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003330 }
3331
Johan Hedberge3846622013-01-09 15:29:33 +02003332 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3333 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003334
3335failed:
3336 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003337 return err;
3338}
3339
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003340static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003341 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003342{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003343 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003344 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003345 int err;
3346
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003347 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003348
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003349 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003350 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3351 MGMT_STATUS_INVALID_PARAMS,
3352 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003353
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003354 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003355
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003356 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003357 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003358 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003359 else
Szymon Janca6785be2012-12-13 15:11:21 +01003360 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003361
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003362 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003363 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003364
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003365 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003366
3367 return err;
3368}
3369
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003370static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003371 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003372{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003373 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003374 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003375 int err;
3376
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003377 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003378
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003379 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003380 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3381 MGMT_STATUS_INVALID_PARAMS,
3382 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003383
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003384 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003385
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003386 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003387 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003388 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003389 else
Szymon Janca6785be2012-12-13 15:11:21 +01003390 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003391
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003392 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003393 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003394
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003395 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003396
3397 return err;
3398}
3399
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003400static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3401 u16 len)
3402{
3403 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003404 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003405 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003406 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003407
3408 BT_DBG("%s", hdev->name);
3409
Szymon Jancc72d4b82012-03-16 16:02:57 +01003410 source = __le16_to_cpu(cp->source);
3411
3412 if (source > 0x0002)
3413 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3414 MGMT_STATUS_INVALID_PARAMS);
3415
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003416 hci_dev_lock(hdev);
3417
Szymon Jancc72d4b82012-03-16 16:02:57 +01003418 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003419 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3420 hdev->devid_product = __le16_to_cpu(cp->product);
3421 hdev->devid_version = __le16_to_cpu(cp->version);
3422
3423 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3424
Johan Hedberg890ea892013-03-15 17:06:52 -05003425 hci_req_init(&req, hdev);
3426 update_eir(&req);
3427 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003428
3429 hci_dev_unlock(hdev);
3430
3431 return err;
3432}
3433
Johan Hedberg4375f102013-09-25 13:26:10 +03003434static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3435{
3436 struct cmd_lookup match = { NULL, hdev };
3437
3438 if (status) {
3439 u8 mgmt_err = mgmt_status(status);
3440
3441 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3442 cmd_status_rsp, &mgmt_err);
3443 return;
3444 }
3445
3446 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3447 &match);
3448
3449 new_settings(hdev, match.sk);
3450
3451 if (match.sk)
3452 sock_put(match.sk);
3453}
3454
Marcel Holtmann21b51872013-10-10 09:47:53 -07003455static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3456 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003457{
3458 struct mgmt_mode *cp = data;
3459 struct pending_cmd *cmd;
3460 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003461 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003462 int err;
3463
3464 BT_DBG("request for %s", hdev->name);
3465
Johan Hedberge6fe7982013-10-02 15:45:22 +03003466 status = mgmt_le_support(hdev);
3467 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003468 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003469 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003470
3471 if (cp->val != 0x00 && cp->val != 0x01)
3472 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3473 MGMT_STATUS_INVALID_PARAMS);
3474
3475 hci_dev_lock(hdev);
3476
3477 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003478 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003479
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003480 /* The following conditions are ones which mean that we should
3481 * not do any HCI communication but directly send a mgmt
3482 * response to user space (after toggling the flag if
3483 * necessary).
3484 */
3485 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003486 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003487 bool changed = false;
3488
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003489 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3490 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003491 changed = true;
3492 }
3493
3494 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3495 if (err < 0)
3496 goto unlock;
3497
3498 if (changed)
3499 err = new_settings(hdev, sk);
3500
3501 goto unlock;
3502 }
3503
3504 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3505 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3506 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3507 MGMT_STATUS_BUSY);
3508 goto unlock;
3509 }
3510
3511 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3512 if (!cmd) {
3513 err = -ENOMEM;
3514 goto unlock;
3515 }
3516
3517 hci_req_init(&req, hdev);
3518
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003519 if (val)
3520 enable_advertising(&req);
3521 else
3522 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003523
3524 err = hci_req_run(&req, set_advertising_complete);
3525 if (err < 0)
3526 mgmt_pending_remove(cmd);
3527
3528unlock:
3529 hci_dev_unlock(hdev);
3530 return err;
3531}
3532
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003533static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3534 void *data, u16 len)
3535{
3536 struct mgmt_cp_set_static_address *cp = data;
3537 int err;
3538
3539 BT_DBG("%s", hdev->name);
3540
Marcel Holtmann62af4442013-10-02 22:10:32 -07003541 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003542 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003543 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003544
3545 if (hdev_is_powered(hdev))
3546 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3547 MGMT_STATUS_REJECTED);
3548
3549 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3550 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3551 return cmd_status(sk, hdev->id,
3552 MGMT_OP_SET_STATIC_ADDRESS,
3553 MGMT_STATUS_INVALID_PARAMS);
3554
3555 /* Two most significant bits shall be set */
3556 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3557 return cmd_status(sk, hdev->id,
3558 MGMT_OP_SET_STATIC_ADDRESS,
3559 MGMT_STATUS_INVALID_PARAMS);
3560 }
3561
3562 hci_dev_lock(hdev);
3563
3564 bacpy(&hdev->static_addr, &cp->bdaddr);
3565
3566 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3567
3568 hci_dev_unlock(hdev);
3569
3570 return err;
3571}
3572
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003573static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3574 void *data, u16 len)
3575{
3576 struct mgmt_cp_set_scan_params *cp = data;
3577 __u16 interval, window;
3578 int err;
3579
3580 BT_DBG("%s", hdev->name);
3581
3582 if (!lmp_le_capable(hdev))
3583 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3584 MGMT_STATUS_NOT_SUPPORTED);
3585
3586 interval = __le16_to_cpu(cp->interval);
3587
3588 if (interval < 0x0004 || interval > 0x4000)
3589 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3590 MGMT_STATUS_INVALID_PARAMS);
3591
3592 window = __le16_to_cpu(cp->window);
3593
3594 if (window < 0x0004 || window > 0x4000)
3595 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3596 MGMT_STATUS_INVALID_PARAMS);
3597
Marcel Holtmann899e1072013-10-14 09:55:32 -07003598 if (window > interval)
3599 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3600 MGMT_STATUS_INVALID_PARAMS);
3601
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003602 hci_dev_lock(hdev);
3603
3604 hdev->le_scan_interval = interval;
3605 hdev->le_scan_window = window;
3606
3607 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3608
3609 hci_dev_unlock(hdev);
3610
3611 return err;
3612}
3613
Johan Hedberg33e38b32013-03-15 17:07:05 -05003614static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3615{
3616 struct pending_cmd *cmd;
3617
3618 BT_DBG("status 0x%02x", status);
3619
3620 hci_dev_lock(hdev);
3621
3622 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3623 if (!cmd)
3624 goto unlock;
3625
3626 if (status) {
3627 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3628 mgmt_status(status));
3629 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003630 struct mgmt_mode *cp = cmd->param;
3631
3632 if (cp->val)
3633 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3634 else
3635 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3636
Johan Hedberg33e38b32013-03-15 17:07:05 -05003637 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3638 new_settings(hdev, cmd->sk);
3639 }
3640
3641 mgmt_pending_remove(cmd);
3642
3643unlock:
3644 hci_dev_unlock(hdev);
3645}
3646
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003647static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003648 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003649{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003650 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003651 struct pending_cmd *cmd;
3652 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003653 int err;
3654
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003655 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003656
Johan Hedberg56f87902013-10-02 13:43:13 +03003657 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3658 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003659 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3660 MGMT_STATUS_NOT_SUPPORTED);
3661
Johan Hedberga7e80f22013-01-09 16:05:19 +02003662 if (cp->val != 0x00 && cp->val != 0x01)
3663 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3664 MGMT_STATUS_INVALID_PARAMS);
3665
Johan Hedberg5400c042012-02-21 16:40:33 +02003666 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003667 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003668 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003669
3670 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003671 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003672 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003673
3674 hci_dev_lock(hdev);
3675
Johan Hedberg05cbf292013-03-15 17:07:07 -05003676 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3677 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3678 MGMT_STATUS_BUSY);
3679 goto unlock;
3680 }
3681
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003682 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3683 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3684 hdev);
3685 goto unlock;
3686 }
3687
Johan Hedberg33e38b32013-03-15 17:07:05 -05003688 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3689 data, len);
3690 if (!cmd) {
3691 err = -ENOMEM;
3692 goto unlock;
3693 }
3694
3695 hci_req_init(&req, hdev);
3696
Johan Hedberg406d7802013-03-15 17:07:09 -05003697 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003698
3699 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003700 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003701 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003702 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003703 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003704 }
3705
Johan Hedberg33e38b32013-03-15 17:07:05 -05003706unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003707 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003708
Antti Julkuf6422ec2011-06-22 13:11:56 +03003709 return err;
3710}
3711
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003712static void set_bredr_scan(struct hci_request *req)
3713{
3714 struct hci_dev *hdev = req->hdev;
3715 u8 scan = 0;
3716
3717 /* Ensure that fast connectable is disabled. This function will
3718 * not do anything if the page scan parameters are already what
3719 * they should be.
3720 */
3721 write_fast_connectable(req, false);
3722
3723 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3724 scan |= SCAN_PAGE;
3725 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3726 scan |= SCAN_INQUIRY;
3727
3728 if (scan)
3729 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3730}
3731
Johan Hedberg0663ca22013-10-02 13:43:14 +03003732static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3733{
3734 struct pending_cmd *cmd;
3735
3736 BT_DBG("status 0x%02x", status);
3737
3738 hci_dev_lock(hdev);
3739
3740 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3741 if (!cmd)
3742 goto unlock;
3743
3744 if (status) {
3745 u8 mgmt_err = mgmt_status(status);
3746
3747 /* We need to restore the flag if related HCI commands
3748 * failed.
3749 */
3750 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3751
3752 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3753 } else {
3754 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3755 new_settings(hdev, cmd->sk);
3756 }
3757
3758 mgmt_pending_remove(cmd);
3759
3760unlock:
3761 hci_dev_unlock(hdev);
3762}
3763
3764static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3765{
3766 struct mgmt_mode *cp = data;
3767 struct pending_cmd *cmd;
3768 struct hci_request req;
3769 int err;
3770
3771 BT_DBG("request for %s", hdev->name);
3772
3773 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3774 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3775 MGMT_STATUS_NOT_SUPPORTED);
3776
3777 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3778 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3779 MGMT_STATUS_REJECTED);
3780
3781 if (cp->val != 0x00 && cp->val != 0x01)
3782 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3783 MGMT_STATUS_INVALID_PARAMS);
3784
3785 hci_dev_lock(hdev);
3786
3787 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3788 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3789 goto unlock;
3790 }
3791
3792 if (!hdev_is_powered(hdev)) {
3793 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003794 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3795 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3796 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3797 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3798 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3799 }
3800
3801 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3802
3803 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3804 if (err < 0)
3805 goto unlock;
3806
3807 err = new_settings(hdev, sk);
3808 goto unlock;
3809 }
3810
3811 /* Reject disabling when powered on */
3812 if (!cp->val) {
3813 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3814 MGMT_STATUS_REJECTED);
3815 goto unlock;
3816 }
3817
3818 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3819 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3820 MGMT_STATUS_BUSY);
3821 goto unlock;
3822 }
3823
3824 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3825 if (!cmd) {
3826 err = -ENOMEM;
3827 goto unlock;
3828 }
3829
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07003830 /* We need to flip the bit already here so that update_ad
Johan Hedberg0663ca22013-10-02 13:43:14 +03003831 * generates the correct flags.
3832 */
3833 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3834
3835 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003836
3837 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3838 set_bredr_scan(&req);
3839
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07003840 update_ad(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003841
Johan Hedberg0663ca22013-10-02 13:43:14 +03003842 err = hci_req_run(&req, set_bredr_complete);
3843 if (err < 0)
3844 mgmt_pending_remove(cmd);
3845
3846unlock:
3847 hci_dev_unlock(hdev);
3848 return err;
3849}
3850
Johan Hedberg3f706b72013-01-20 14:27:16 +02003851static bool ltk_is_valid(struct mgmt_ltk_info *key)
3852{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003853 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3854 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003855 if (key->master != 0x00 && key->master != 0x01)
3856 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003857 if (!bdaddr_type_is_le(key->addr.type))
3858 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003859 return true;
3860}
3861
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003862static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003863 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003864{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003865 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3866 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003867 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003868
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003869 BT_DBG("request for %s", hdev->name);
3870
3871 if (!lmp_le_capable(hdev))
3872 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3873 MGMT_STATUS_NOT_SUPPORTED);
3874
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003875 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003876
3877 expected_len = sizeof(*cp) + key_count *
3878 sizeof(struct mgmt_ltk_info);
3879 if (expected_len != len) {
3880 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003881 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003882 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003883 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003884 }
3885
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003886 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003887
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003888 for (i = 0; i < key_count; i++) {
3889 struct mgmt_ltk_info *key = &cp->keys[i];
3890
Johan Hedberg3f706b72013-01-20 14:27:16 +02003891 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003892 return cmd_status(sk, hdev->id,
3893 MGMT_OP_LOAD_LONG_TERM_KEYS,
3894 MGMT_STATUS_INVALID_PARAMS);
3895 }
3896
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003897 hci_dev_lock(hdev);
3898
3899 hci_smp_ltks_clear(hdev);
3900
3901 for (i = 0; i < key_count; i++) {
3902 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003903 u8 type, addr_type;
3904
3905 if (key->addr.type == BDADDR_LE_PUBLIC)
3906 addr_type = ADDR_LE_DEV_PUBLIC;
3907 else
3908 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003909
3910 if (key->master)
3911 type = HCI_SMP_LTK;
3912 else
3913 type = HCI_SMP_LTK_SLAVE;
3914
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003915 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003916 type, 0, key->authenticated, key->val,
3917 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003918 }
3919
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003920 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3921 NULL, 0);
3922
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003923 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003924
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003925 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003926}
3927
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003928static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003929 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3930 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003931 bool var_len;
3932 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003933} mgmt_handlers[] = {
3934 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003935 { read_version, false, MGMT_READ_VERSION_SIZE },
3936 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3937 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3938 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3939 { set_powered, false, MGMT_SETTING_SIZE },
3940 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3941 { set_connectable, false, MGMT_SETTING_SIZE },
3942 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3943 { set_pairable, false, MGMT_SETTING_SIZE },
3944 { set_link_security, false, MGMT_SETTING_SIZE },
3945 { set_ssp, false, MGMT_SETTING_SIZE },
3946 { set_hs, false, MGMT_SETTING_SIZE },
3947 { set_le, false, MGMT_SETTING_SIZE },
3948 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3949 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3950 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3951 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3952 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3953 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3954 { disconnect, false, MGMT_DISCONNECT_SIZE },
3955 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3956 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3957 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3958 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3959 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3960 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3961 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3962 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3963 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3964 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3965 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3966 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3967 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3968 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3969 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3970 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3971 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3972 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3973 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003974 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003975 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003976 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003977 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003978 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003979};
3980
3981
Johan Hedberg03811012010-12-08 00:21:06 +02003982int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3983{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003984 void *buf;
3985 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003986 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003987 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003988 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003989 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003990 int err;
3991
3992 BT_DBG("got %zu bytes", msglen);
3993
3994 if (msglen < sizeof(*hdr))
3995 return -EINVAL;
3996
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003997 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003998 if (!buf)
3999 return -ENOMEM;
4000
4001 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4002 err = -EFAULT;
4003 goto done;
4004 }
4005
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004006 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004007 opcode = __le16_to_cpu(hdr->opcode);
4008 index = __le16_to_cpu(hdr->index);
4009 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004010
4011 if (len != msglen - sizeof(*hdr)) {
4012 err = -EINVAL;
4013 goto done;
4014 }
4015
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004016 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004017 hdev = hci_dev_get(index);
4018 if (!hdev) {
4019 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004020 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004021 goto done;
4022 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004023
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004024 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4025 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004026 err = cmd_status(sk, index, opcode,
4027 MGMT_STATUS_INVALID_INDEX);
4028 goto done;
4029 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004030 }
4031
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004032 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004033 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004034 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004035 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004036 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004037 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004038 }
4039
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004040 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004041 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004042 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004043 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004044 goto done;
4045 }
4046
Johan Hedbergbe22b542012-03-01 22:24:41 +02004047 handler = &mgmt_handlers[opcode];
4048
4049 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004050 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004051 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004052 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004053 goto done;
4054 }
4055
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004056 if (hdev)
4057 mgmt_init_hdev(sk, hdev);
4058
4059 cp = buf + sizeof(*hdr);
4060
Johan Hedbergbe22b542012-03-01 22:24:41 +02004061 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004062 if (err < 0)
4063 goto done;
4064
Johan Hedberg03811012010-12-08 00:21:06 +02004065 err = msglen;
4066
4067done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004068 if (hdev)
4069 hci_dev_put(hdev);
4070
Johan Hedberg03811012010-12-08 00:21:06 +02004071 kfree(buf);
4072 return err;
4073}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004074
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004075void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004076{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004077 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004078 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004079
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004080 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004081}
4082
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004083void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004084{
Johan Hedberg5f159032012-03-02 03:13:19 +02004085 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004086
Marcel Holtmann1514b892013-10-06 08:25:01 -07004087 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004088 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004089
Johan Hedberg744cf192011-11-08 20:40:14 +02004090 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004091
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004092 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004093}
4094
Johan Hedberg229ab392013-03-15 17:06:53 -05004095static void powered_complete(struct hci_dev *hdev, u8 status)
4096{
4097 struct cmd_lookup match = { NULL, hdev };
4098
4099 BT_DBG("status 0x%02x", status);
4100
4101 hci_dev_lock(hdev);
4102
4103 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4104
4105 new_settings(hdev, match.sk);
4106
4107 hci_dev_unlock(hdev);
4108
4109 if (match.sk)
4110 sock_put(match.sk);
4111}
4112
Johan Hedberg70da6242013-03-15 17:06:51 -05004113static int powered_update_hci(struct hci_dev *hdev)
4114{
Johan Hedberg890ea892013-03-15 17:06:52 -05004115 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004116 u8 link_sec;
4117
Johan Hedberg890ea892013-03-15 17:06:52 -05004118 hci_req_init(&req, hdev);
4119
Johan Hedberg70da6242013-03-15 17:06:51 -05004120 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4121 !lmp_host_ssp_capable(hdev)) {
4122 u8 ssp = 1;
4123
Johan Hedberg890ea892013-03-15 17:06:52 -05004124 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004125 }
4126
Johan Hedbergc73eee92013-04-19 18:35:21 +03004127 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4128 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004129 struct hci_cp_write_le_host_supported cp;
4130
4131 cp.le = 1;
4132 cp.simul = lmp_le_br_capable(hdev);
4133
4134 /* Check first if we already have the right
4135 * host state (host features set)
4136 */
4137 if (cp.le != lmp_host_le_capable(hdev) ||
4138 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004139 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4140 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004141 }
4142
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004143 if (lmp_le_capable(hdev)) {
4144 /* Set random address to static address if configured */
4145 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4146 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4147 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004148
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004149 /* Make sure the controller has a good default for
4150 * advertising data. This also applies to the case
4151 * where BR/EDR was toggled during the AUTO_OFF phase.
4152 */
4153 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
4154 update_ad(&req);
4155
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004156 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4157 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004158 }
4159
Johan Hedberg70da6242013-03-15 17:06:51 -05004160 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4161 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004162 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4163 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004164
4165 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004166 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4167 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004168 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004169 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004170 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004171 }
4172
Johan Hedberg229ab392013-03-15 17:06:53 -05004173 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004174}
4175
Johan Hedberg744cf192011-11-08 20:40:14 +02004176int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004177{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004178 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004179 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4180 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004181 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004182
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004183 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4184 return 0;
4185
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004186 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004187 if (powered_update_hci(hdev) == 0)
4188 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004189
Johan Hedberg229ab392013-03-15 17:06:53 -05004190 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4191 &match);
4192 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004193 }
4194
Johan Hedberg229ab392013-03-15 17:06:53 -05004195 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4196 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4197
4198 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4199 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4200 zero_cod, sizeof(zero_cod), NULL);
4201
4202new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004203 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004204
4205 if (match.sk)
4206 sock_put(match.sk);
4207
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004208 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004209}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004210
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004211void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004212{
4213 struct pending_cmd *cmd;
4214 u8 status;
4215
4216 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4217 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004218 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004219
4220 if (err == -ERFKILL)
4221 status = MGMT_STATUS_RFKILLED;
4222 else
4223 status = MGMT_STATUS_FAILED;
4224
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004225 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004226
4227 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004228}
4229
Marcel Holtmann86a75642013-10-15 06:33:54 -07004230void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004231{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004232 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004233
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004234 /* Nothing needed here if there's a pending command since that
4235 * commands request completion callback takes care of everything
4236 * necessary.
4237 */
4238 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004239 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004240
Marcel Holtmann86a75642013-10-15 06:33:54 -07004241 if (discoverable)
4242 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4243 else
4244 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004245
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004246 if (changed)
Marcel Holtmann86a75642013-10-15 06:33:54 -07004247 new_settings(hdev, NULL);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004248}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004249
Johan Hedberg744cf192011-11-08 20:40:14 +02004250int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004251{
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004252 bool changed = false;
4253 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004254
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004255 /* Nothing needed here if there's a pending command since that
4256 * commands request completion callback takes care of everything
4257 * necessary.
4258 */
4259 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
4260 return 0;
4261
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004262 if (connectable) {
4263 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4264 changed = true;
4265 } else {
4266 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4267 changed = true;
4268 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004269
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004270 if (changed)
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004271 err = new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004272
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004273 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004274}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004275
Johan Hedberg744cf192011-11-08 20:40:14 +02004276int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004277{
Johan Hedbergca69b792011-11-11 18:10:00 +02004278 u8 mgmt_err = mgmt_status(status);
4279
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004280 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004281 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004282 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004283
4284 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004285 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004286 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004287
4288 return 0;
4289}
4290
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004291int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4292 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004293{
Johan Hedberg86742e12011-11-07 23:13:38 +02004294 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004295
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004296 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004297
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004298 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004299 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004300 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004301 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004302 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004303 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004304
Johan Hedberg744cf192011-11-08 20:40:14 +02004305 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004306}
Johan Hedbergf7520542011-01-20 12:34:39 +02004307
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004308int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4309{
4310 struct mgmt_ev_new_long_term_key ev;
4311
4312 memset(&ev, 0, sizeof(ev));
4313
4314 ev.store_hint = persistent;
4315 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004316 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004317 ev.key.authenticated = key->authenticated;
4318 ev.key.enc_size = key->enc_size;
4319 ev.key.ediv = key->ediv;
4320
4321 if (key->type == HCI_SMP_LTK)
4322 ev.key.master = 1;
4323
4324 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4325 memcpy(ev.key.val, key->val, sizeof(key->val));
4326
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004327 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4328 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004329}
4330
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004331void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4332 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4333 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004334{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004335 char buf[512];
4336 struct mgmt_ev_device_connected *ev = (void *) buf;
4337 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004338
Johan Hedbergb644ba32012-01-17 21:48:47 +02004339 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004340 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004341
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004342 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004343
Johan Hedbergb644ba32012-01-17 21:48:47 +02004344 if (name_len > 0)
4345 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004346 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004347
4348 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004349 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004350 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004351
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004352 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004353
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004354 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4355 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004356}
4357
Johan Hedberg8962ee72011-01-20 12:40:27 +02004358static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4359{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004360 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004361 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004362 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004363
Johan Hedberg88c3df12012-02-09 14:27:38 +02004364 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4365 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004366
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004367 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004368 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004369
4370 *sk = cmd->sk;
4371 sock_hold(*sk);
4372
Johan Hedberga664b5b2011-02-19 12:06:02 -03004373 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004374}
4375
Johan Hedberg124f6e32012-02-09 13:50:12 +02004376static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004377{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004378 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004379 struct mgmt_cp_unpair_device *cp = cmd->param;
4380 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004381
4382 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004383 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4384 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004385
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004386 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4387
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004388 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004389
4390 mgmt_pending_remove(cmd);
4391}
4392
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004393void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4394 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004395{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004396 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004397 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004398
Johan Hedberg744cf192011-11-08 20:40:14 +02004399 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004400
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004401 bacpy(&ev.addr.bdaddr, bdaddr);
4402 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4403 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004404
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004405 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004406
4407 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004408 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004409
Johan Hedberg124f6e32012-02-09 13:50:12 +02004410 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004411 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004412}
4413
Marcel Holtmann78929242013-10-06 23:55:47 -07004414void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4415 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004416{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004417 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004418 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004419
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004420 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4421 hdev);
4422
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004423 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004424 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004425 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004426
Johan Hedberg88c3df12012-02-09 14:27:38 +02004427 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004428 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004429
Marcel Holtmann78929242013-10-06 23:55:47 -07004430 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4431 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004432
Johan Hedberga664b5b2011-02-19 12:06:02 -03004433 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004434}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004435
Marcel Holtmann445608d2013-10-06 23:55:48 -07004436void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4437 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004438{
4439 struct mgmt_ev_connect_failed ev;
4440
Johan Hedberg4c659c32011-11-07 23:13:39 +02004441 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004442 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004443 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004444
Marcel Holtmann445608d2013-10-06 23:55:48 -07004445 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004446}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004447
Johan Hedberg744cf192011-11-08 20:40:14 +02004448int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004449{
4450 struct mgmt_ev_pin_code_request ev;
4451
Johan Hedbergd8457692012-02-17 14:24:57 +02004452 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004453 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004454 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004455
Johan Hedberg744cf192011-11-08 20:40:14 +02004456 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004457 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004458}
4459
Johan Hedberg744cf192011-11-08 20:40:14 +02004460int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004461 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004462{
4463 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004464 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004465 int err;
4466
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004467 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004468 if (!cmd)
4469 return -ENOENT;
4470
Johan Hedbergd8457692012-02-17 14:24:57 +02004471 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004472 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004473
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004474 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004475 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004476
Johan Hedberga664b5b2011-02-19 12:06:02 -03004477 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004478
4479 return err;
4480}
4481
Johan Hedberg744cf192011-11-08 20:40:14 +02004482int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004483 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004484{
4485 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004486 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004487 int err;
4488
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004489 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004490 if (!cmd)
4491 return -ENOENT;
4492
Johan Hedbergd8457692012-02-17 14:24:57 +02004493 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004494 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004495
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004496 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004497 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004498
Johan Hedberga664b5b2011-02-19 12:06:02 -03004499 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004500
4501 return err;
4502}
Johan Hedberga5c29682011-02-19 12:05:57 -03004503
Johan Hedberg744cf192011-11-08 20:40:14 +02004504int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004505 u8 link_type, u8 addr_type, __le32 value,
4506 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004507{
4508 struct mgmt_ev_user_confirm_request ev;
4509
Johan Hedberg744cf192011-11-08 20:40:14 +02004510 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004511
Johan Hedberg272d90d2012-02-09 15:26:12 +02004512 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004513 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004514 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02004515 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004516
Johan Hedberg744cf192011-11-08 20:40:14 +02004517 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004518 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004519}
4520
Johan Hedberg272d90d2012-02-09 15:26:12 +02004521int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004522 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004523{
4524 struct mgmt_ev_user_passkey_request ev;
4525
4526 BT_DBG("%s", hdev->name);
4527
Johan Hedberg272d90d2012-02-09 15:26:12 +02004528 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004529 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004530
4531 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004532 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004533}
4534
Brian Gix0df4c182011-11-16 13:53:13 -08004535static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004536 u8 link_type, u8 addr_type, u8 status,
4537 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004538{
4539 struct pending_cmd *cmd;
4540 struct mgmt_rp_user_confirm_reply rp;
4541 int err;
4542
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004543 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004544 if (!cmd)
4545 return -ENOENT;
4546
Johan Hedberg272d90d2012-02-09 15:26:12 +02004547 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004548 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004549 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004550 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004551
Johan Hedberga664b5b2011-02-19 12:06:02 -03004552 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004553
4554 return err;
4555}
4556
Johan Hedberg744cf192011-11-08 20:40:14 +02004557int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004558 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004559{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004560 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004561 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004562}
4563
Johan Hedberg272d90d2012-02-09 15:26:12 +02004564int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004565 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004566{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004567 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004568 status,
4569 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004570}
Johan Hedberg2a611692011-02-19 12:06:00 -03004571
Brian Gix604086b2011-11-23 08:28:33 -08004572int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004573 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004574{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004575 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004576 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004577}
4578
Johan Hedberg272d90d2012-02-09 15:26:12 +02004579int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004580 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004581{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004582 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004583 status,
4584 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004585}
4586
Johan Hedberg92a25252012-09-06 18:39:26 +03004587int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4588 u8 link_type, u8 addr_type, u32 passkey,
4589 u8 entered)
4590{
4591 struct mgmt_ev_passkey_notify ev;
4592
4593 BT_DBG("%s", hdev->name);
4594
4595 bacpy(&ev.addr.bdaddr, bdaddr);
4596 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4597 ev.passkey = __cpu_to_le32(passkey);
4598 ev.entered = entered;
4599
4600 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4601}
4602
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004603int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004604 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004605{
4606 struct mgmt_ev_auth_failed ev;
4607
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004608 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004609 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004610 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004611
Johan Hedberg744cf192011-11-08 20:40:14 +02004612 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004613}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004614
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004615int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4616{
4617 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004618 bool changed = false;
4619 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004620
4621 if (status) {
4622 u8 mgmt_err = mgmt_status(status);
4623 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004624 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004625 return 0;
4626 }
4627
Johan Hedberg47990ea2012-02-22 11:58:37 +02004628 if (test_bit(HCI_AUTH, &hdev->flags)) {
4629 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4630 changed = true;
4631 } else {
4632 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4633 changed = true;
4634 }
4635
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004636 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004637 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004638
Johan Hedberg47990ea2012-02-22 11:58:37 +02004639 if (changed)
4640 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004641
4642 if (match.sk)
4643 sock_put(match.sk);
4644
4645 return err;
4646}
4647
Johan Hedberg890ea892013-03-15 17:06:52 -05004648static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004649{
Johan Hedberg890ea892013-03-15 17:06:52 -05004650 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004651 struct hci_cp_write_eir cp;
4652
Johan Hedberg976eb202012-10-24 21:12:01 +03004653 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004654 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004655
Johan Hedbergc80da272012-02-22 15:38:48 +02004656 memset(hdev->eir, 0, sizeof(hdev->eir));
4657
Johan Hedbergcacaf522012-02-21 00:52:42 +02004658 memset(&cp, 0, sizeof(cp));
4659
Johan Hedberg890ea892013-03-15 17:06:52 -05004660 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004661}
4662
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004663int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004664{
4665 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004666 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004667 bool changed = false;
4668 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004669
4670 if (status) {
4671 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004672
4673 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004674 &hdev->dev_flags)) {
4675 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004676 err = new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004677 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004678
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004679 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4680 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004681
4682 return err;
4683 }
4684
4685 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004686 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004687 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004688 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4689 if (!changed)
4690 changed = test_and_clear_bit(HCI_HS_ENABLED,
4691 &hdev->dev_flags);
4692 else
4693 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004694 }
4695
4696 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4697
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004698 if (changed)
4699 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004700
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004701 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004702 sock_put(match.sk);
4703
Johan Hedberg890ea892013-03-15 17:06:52 -05004704 hci_req_init(&req, hdev);
4705
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004706 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004707 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004708 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004709 clear_eir(&req);
4710
4711 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004712
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004713 return err;
4714}
4715
Johan Hedberg92da6092013-03-15 17:06:55 -05004716static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004717{
4718 struct cmd_lookup *match = data;
4719
Johan Hedberg90e70452012-02-23 23:09:40 +02004720 if (match->sk == NULL) {
4721 match->sk = cmd->sk;
4722 sock_hold(match->sk);
4723 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004724}
4725
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004726int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004727 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004728{
Johan Hedberg90e70452012-02-23 23:09:40 +02004729 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4730 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004731
Johan Hedberg92da6092013-03-15 17:06:55 -05004732 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4733 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4734 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004735
4736 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004737 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4738 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004739
4740 if (match.sk)
4741 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004742
4743 return err;
4744}
4745
Johan Hedberg744cf192011-11-08 20:40:14 +02004746int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004747{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004748 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004749 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004750
Johan Hedberg13928972013-03-15 17:07:00 -05004751 if (status)
4752 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004753
4754 memset(&ev, 0, sizeof(ev));
4755 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004756 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004757
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004758 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004759 if (!cmd) {
4760 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004761
Johan Hedberg13928972013-03-15 17:07:00 -05004762 /* If this is a HCI command related to powering on the
4763 * HCI dev don't send any mgmt signals.
4764 */
4765 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4766 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004767 }
4768
Johan Hedberg13928972013-03-15 17:07:00 -05004769 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4770 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004771}
Szymon Jancc35938b2011-03-22 13:12:21 +01004772
Johan Hedberg744cf192011-11-08 20:40:14 +02004773int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004774 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004775{
4776 struct pending_cmd *cmd;
4777 int err;
4778
Johan Hedberg744cf192011-11-08 20:40:14 +02004779 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004780
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004781 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004782 if (!cmd)
4783 return -ENOENT;
4784
4785 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004786 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4787 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004788 } else {
4789 struct mgmt_rp_read_local_oob_data rp;
4790
4791 memcpy(rp.hash, hash, sizeof(rp.hash));
4792 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4793
Johan Hedberg744cf192011-11-08 20:40:14 +02004794 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004795 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4796 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004797 }
4798
4799 mgmt_pending_remove(cmd);
4800
4801 return err;
4802}
Johan Hedberge17acd42011-03-30 23:57:16 +03004803
Marcel Holtmann901801b2013-10-06 23:55:51 -07004804void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4805 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4806 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004807{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004808 char buf[512];
4809 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004810 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004811
Andre Guedes12602d02013-04-30 15:29:40 -03004812 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004813 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004814
Johan Hedberg1dc06092012-01-15 21:01:23 +02004815 /* Leave 5 bytes for a potential CoD field */
4816 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004817 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004818
Johan Hedberg1dc06092012-01-15 21:01:23 +02004819 memset(buf, 0, sizeof(buf));
4820
Johan Hedberge319d2e2012-01-15 19:51:59 +02004821 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004822 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004823 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004824 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304825 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004826 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304827 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004828
Johan Hedberg1dc06092012-01-15 21:01:23 +02004829 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004830 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004831
Johan Hedberg1dc06092012-01-15 21:01:23 +02004832 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4833 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004834 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004835
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004836 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004837 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004838
Marcel Holtmann901801b2013-10-06 23:55:51 -07004839 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004840}
Johan Hedberga88a9652011-03-30 13:18:12 +03004841
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004842void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4843 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004844{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004845 struct mgmt_ev_device_found *ev;
4846 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4847 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004848
Johan Hedbergb644ba32012-01-17 21:48:47 +02004849 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004850
Johan Hedbergb644ba32012-01-17 21:48:47 +02004851 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004852
Johan Hedbergb644ba32012-01-17 21:48:47 +02004853 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004854 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004855 ev->rssi = rssi;
4856
4857 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004858 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004859
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004860 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004861
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004862 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004863}
Johan Hedberg314b2382011-04-27 10:29:57 -04004864
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004865void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004866{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004867 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004868 struct pending_cmd *cmd;
4869
Andre Guedes343fb142011-11-22 17:14:19 -03004870 BT_DBG("%s discovering %u", hdev->name, discovering);
4871
Johan Hedberg164a6e72011-11-01 17:06:44 +02004872 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004873 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004874 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004875 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004876
4877 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004878 u8 type = hdev->discovery.type;
4879
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004880 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4881 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004882 mgmt_pending_remove(cmd);
4883 }
4884
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004885 memset(&ev, 0, sizeof(ev));
4886 ev.type = hdev->discovery.type;
4887 ev.discovering = discovering;
4888
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004889 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004890}
Antti Julku5e762442011-08-25 16:48:02 +03004891
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004892int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004893{
4894 struct pending_cmd *cmd;
4895 struct mgmt_ev_device_blocked ev;
4896
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004897 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004898
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004899 bacpy(&ev.addr.bdaddr, bdaddr);
4900 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004901
Johan Hedberg744cf192011-11-08 20:40:14 +02004902 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004903 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004904}
4905
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004906int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004907{
4908 struct pending_cmd *cmd;
4909 struct mgmt_ev_device_unblocked ev;
4910
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004911 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004912
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004913 bacpy(&ev.addr.bdaddr, bdaddr);
4914 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004915
Johan Hedberg744cf192011-11-08 20:40:14 +02004916 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004917 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004918}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004919
4920static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4921{
4922 BT_DBG("%s status %u", hdev->name, status);
4923
4924 /* Clear the advertising mgmt setting if we failed to re-enable it */
4925 if (status) {
4926 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004927 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004928 }
4929}
4930
4931void mgmt_reenable_advertising(struct hci_dev *hdev)
4932{
4933 struct hci_request req;
4934
Marcel Holtmannb145edc2013-10-10 09:47:54 -07004935 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07004936 return;
4937
4938 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4939 return;
4940
4941 hci_req_init(&req, hdev);
4942 enable_advertising(&req);
4943
4944 /* If this fails we have no option but to let user space know
4945 * that we've disabled advertising.
4946 */
4947 if (hci_req_run(&req, adv_enable_complete) < 0) {
4948 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004949 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004950 }
4951}